Sign-in and access
Every install has one sign-in service (veltro-identity), and no product has
a login of its own. People sign in at /login. The gateway then hands each
product a short-lived signed statement of who is asking, and that is the only
way into a product. With one product installed, the sign-in page carries that
product’s name. / is Home, which lists what needs you in the products you
use, and the setup steps a product still needs.
Your first sign-in
Section titled “Your first sign-in”Name your first admin before the first start. veltro install asks for the
email, or pass --admin-email you@example.com. It’s saved in .env as
VELTRO_BOOTSTRAP_ADMIN_EMAIL. On Kubernetes, set bootstrapAdminEmail on
the veltro-identity chart (veltro-identity.bootstrapAdminEmail in the
veltro chart).
When identity starts and there’s no admin yet, it creates that admin, with the admin role in every installed product, and logs a one-time link:
First admin created: you@example.com. Set your password (valid 24h, single use): https://soc.example.com/invite/<token>Find it with veltro logs veltro, or in the install directory:
docker compose --env-file versions.env --env-file .env logs veltro | grep 'First admin'kubectl -n <namespace> logs deploy/<release>-veltro-identity-server | grep 'First admin'Open the link and choose a password (12 to 128 characters), and you’re signed
in. The link works once and expires after 24 hours. If it expires first,
restart identity and it logs a new one. Once any admin exists,
VELTRO_BOOTSTRAP_ADMIN_EMAIL does nothing, so you can leave it set.
Adding users
Section titled “Adding users”In Settings > Users, Add user gives you a one-time link for the new user.
It’s shown once, and Veltro doesn’t email it, so copy it and send it yourself.
Give them a role in at least one product first (see Grants below), or they
can’t sign in. The user opens the link and sets a password. They’re signed in
straight away unless they have TOTP, in which case they sign in at /login.
A user added as disabled gets no link. Enable them, then choose Get a new invite link. Do the same if a link expires or gets lost; the old link stops working. The user’s drawer shows Sign-in: not set up yet until they’ve used it.
Links are only for users who can’t sign in yet. You can’t get one for a user who already has a password, a passkey or an SSO login, or whom SCIM manages, and an open link stops working once its user sets any of those up. People who sign in with SSO don’t need one.
Grants
Section titled “Grants”Access to a product comes only from a grant: a product, a role in that product, and either the whole install or one team. Apart from the first admin, administrators of the install get no product access by default, so grant yourself and your users a role in each installed product in Settings > Users. A revoked grant or a disabled user is refused on their next request.
What a role may do inside a product is that product’s business, and each product documents its roles.
Single sign-on and provisioning
Section titled “Single sign-on and provisioning”Settings also configures:
- OIDC and SAML identity providers, with group mappings that turn IdP groups into grants
- SCIM, so your IdP creates, updates and deactivates users
- passkeys and TOTP for people who sign in with a password
- personal access tokens, for MCP clients
IdP groups only ever become grants. They never create teams.
Locked out
Section titled “Locked out”If no admin can sign in (a lost password, a forced reset or a lockout), run this with an existing admin’s email:
veltro admin reset --email you@example.comAdd --dir when you’re not in the install directory. --dry-run prints the
Compose command it runs, which you can also run yourself:
docker compose --env-file versions.env --env-file .env run --rm --no-deps veltro admin-reset --email you@example.com.
On Kubernetes:
kubectl -n <namespace> exec deploy/<release>-veltro-identity-server -- node admin-reset --email you@example.comIt prints Invite for you@example.com (valid 24h, single use): <link>.
Opening the link sets a new password and clears a forced reset or lockout.
TOTP stays on, so you’ll still need your authenticator to sign in.
admin-reset refuses an email that doesn’t belong to an enabled admin.
Assign the bootstrap operator on an existing install
Section titled “Assign the bootstrap operator on an existing install”If the install already has an admin but no bootstrap operator assignment, choose an existing, enabled suite admin:
veltro operator-assign --email you@example.comAdd --dir outside the install directory. --dry-run checks email syntax and
prints the Compose command. It doesn’t check whether the account exists, is
enabled, or is an admin:
docker compose --env-file versions.env --env-file .env run --rm --no-deps veltro operator-assign --email you@example.comFor a Helm install:
kubectl -n <namespace> exec deploy/<release>-veltro-identity-server -- node operator-assign --email you@example.comThe command uses identity’s runtime database connection. It doesn’t need the migration owner’s credentials or print secrets. Missing users, non-admins and disabled users are refused with exit status 1.
Assignment is permanent and happens once. If an assignment already exists,
the command prints its email and leaves it unchanged. Identity automatically
delivers the assignment to VectorFlow and retries until ACK, including after
downtime or a lost response. An authenticated request to
GET /api/suite/peer-reads shows bootstrapOperator.status: pending means
delivery is waiting, ready means the ACK is durable, and refused needs
investigation. The command doesn’t wait for delivery.
How invite links are protected
Section titled “How invite links are protected”Each link holds 256 random bits, and identity stores only a SHA-256 hash of
it, so a database dump can’t be turned back into a working link. A link
expires after 24 hours and works once, and a user has at most one open link
at a time. Creating, using, expiring and replacing a link are all in the audit
log as identity.invite.* events. The link page doesn’t ask for an email and
answers every bad link the same way, so it can’t be used to find out who has
an account.
The gateway’s access log records the path as /invite/[redacted], so the
token stays out of it.