Accounts and Sign-in
Local and SSO accounts, how the first admin comes to be, the Single sign-on settings, the trusted reverse proxy, and the Helm values behind each
Berserk ships with no default credentials. The gateway owns sign-in: it creates the first admin, runs every sign-in, and hands the UI and the other services a token it signs, naming who is signed in. Every account is one of two kinds. This page is the reference for both, for the ways an account comes to be, and for the Helm values involved; the step-by-step setup of single sign-on is Guide: Enabling Single Sign-on.
| Account | Signs in with | Comes to be | Managed on |
|---|---|---|---|
| Local account | Email and password | The first admin's bootstrap, or an invite from Settings → Members | Settings → Members |
| SSO account | Your identity provider, over OpenID Connect | Added by email on Settings → Members; created at its first sign-in when the Single sign-on page allows it; or a local account an admin switched over | Settings → Single sign-on, Settings → Members |
A trusted reverse proxy that asserts the signed-in user is a third way in, for installs that already run one. It creates SSO accounts: the proxy is the identity provider there.
Local accounts
A local account signs in with its email and a password of at least 12 characters. The first admin is always a local account. Every other local account comes from an invite: any signed-in member can mint a one-time accept link from Settings → Members (the "Invite member" button); the recipient opens it, sets a password, and is in. There is no mail step, the inviter shares the link. An invite from a non-admin creates a member with no cluster role; attaching a role (admin or member) to an invite takes an admin.
Local accounts work the same whether single sign-on is on or off, so an admin with a password can always sign in to repair single sign-on. For that reason, while single sign-on is on, the last local admin can be neither deleted nor switched to SSO.
SSO accounts
An SSO account signs in through your identity provider and has no password. It comes to be in one of three ways:
- An admin adds it by email on Settings → Members ("Add an SSO member instead" in the invite dialog). The account has no name until its first sign-in fills it from the provider's claims.
- The provider's first sign-in for an unknown email creates it, when New sign-ins create accounts is on in the Single sign-on settings.
- An admin switches a local account to SSO from its detail on Settings → Members: the password goes, sessions and roles stay.
The provider never signs in a local account: a local member who tries "Continue with SSO" is told that the account signs in with a password. While single sign-on is off, SSO accounts stay but cannot sign in until it is on again; nobody who is signed in is signed out. An identity is linked to the account by the provider's issuer and subject; after an issuer change, accounts link again by their verified email at their next sign-in.
An SSO account's cluster role comes from the Single sign-on page's Admin emails, from the role chosen when it was added, or from an admin later, the same as a local account's.
The first admin
The first admin is created once, when the gateway first starts with no accounts. Two ways:
One-time setup link (default)
The gateway prints a single-use link to its container log. The only value it needs is the public URL the link is built from:
global:
publicBaseUrl: "https://berserk.example.com"Read the link from the gateway's log and open it in a browser:
kubectl logs -n bzrk deploy/gateway | grep -A2 "Initial admin setup"The form asks for the admin's email, given name, family name and password. The link works once and expires an hour after it was printed; a restart with no accounts yet prints a fresh one. Once any account exists, /setup answers 410 Gone for good.
The link carries the active token. Treat the gateway's log as a credential until setup is done, and never paste the link into a shared channel.
Pre-provisioned admin
For unattended installs, the chart creates the admin at the first start:
gateway:
bootstrap:
adminEmail: admin@example.com
adminGivenName: Cluster
adminFamilyName: Admin
# adminPassword: pass it with --set, so it stays out of the filehelm install berserk berserk/berserk \
--namespace bzrk \
-f values.yaml \
--set gateway.bootstrap.adminPassword="your-very-strong-password-here"The chart writes the password into the gateway-bootstrap-admin Secret; passing it with --set keeps it out of a checked-in values file, and it must be at least 12 characters. To manage the Secret yourself, create it with the key bootstrap_admin_password and name it:
gateway:
bootstrap:
adminEmail: admin@example.com
adminGivenName: Cluster
adminFamilyName: Admin
existingSecret:
name: berserk-admin
key: bootstrap_admin_passwordThe admin is created on the first start with no accounts and never again: a later change of the password value has no effect, and the setup link is not printed.
Single sign-on settings
Single sign-on is configured on Settings → Single sign-on by a cluster admin, not in Helm values, and needs no Secret: the client secret is entered on the page once and kept sealed under the master key in the gateway's database. The page shows the redirect URI to register at the identity provider, https://<your Berserk URL>/auth/oidc/callback.
| Setting | What it does |
|---|---|
| Issuer URL | The identity provider's issuer, spelled exactly as its discovery document states it, trailing slash included or not. Must be https://. |
| Client ID | The client registered at the provider for Berserk. |
| Client secret | The client's secret, at least 32 characters. Entered once; the page says only whether one is stored. Leave the field blank to keep it. A changed issuer or client ID needs it again. |
| Scopes | Extra scopes to request. openid, email and profile are always requested. |
| Require a verified email | Refuse a sign-in whose email_verified claim is not true. On by default; turn it off only for a provider that verifies emails another way. |
| New sign-ins create accounts | On: a sign-in for an unknown email creates an SSO account. Off: only members added on Settings → Members sign in through the provider. |
| Admin emails | Emails made cluster admin when their account is created, by SSO or by invite. |
| Save | Stores the settings and keeps single sign-on as it is, on or off. |
| Enable SSO, Disable SSO | Turn single sign-on on or off, keeping the settings and the secret. Turning it on, or changing the issuer while it is on, first runs discovery against the issuer, so a misspelled issuer fails on the page. Turning it off never depends on the provider. |
The page warns when single sign-on is on and no local admin exists: if the provider stops working, nobody can sign in to repair it, and recovery needs database access (UPDATE oidc_config SET enabled = FALSE in the gateway's auth database). Keep one admin with a password.
Trusted reverse proxy
When an authenticating reverse proxy already fronts the gateway, it can assert the signed-in user in a request header and Berserk trusts it. Two ways to carry the identity, each enabled on its own and at least one required:
- Direct email header — the proxy forwards the user's email in a header, such as
X-PP-USER. - SPIFFE on-behalf-of — the proxy forwards a SPIFFE identity (
on-behalf-of: spiffe://<trust-domain>/user/<name>); the gateway strips a configured prefix to recover the username and appends a configured email domain.
gateway:
config:
trustedProxy:
enabled: true
# Direct email header; leave empty to disable this way in.
userHeader: X-PP-USER
# SPIFFE on-behalf-of; set enabled: false to disable this way in.
onBehalfOf:
enabled: true
header: on-behalf-of
spiffePrefix: "spiffe://prod.example.net/user/"
emailDomain: example.com
allowedDomains: [] # e.g. [corp.example]
adminEmails: [] # e.g. [admin@corp.example]| Value | Required | What it does |
|---|---|---|
gateway.config.trustedProxy.enabled | yes | Turns the path on. Off by default. |
gateway.config.trustedProxy.userHeader | one of the two ways | Header carrying the asserted email. Must not collide with X-Bzrk-* or the stripped reverse-proxy aliases (X-Forwarded-User, Remote-User, …); the gateway refuses to start if it does. |
gateway.config.trustedProxy.onBehalfOf.enabled | one of the two ways | Turns the SPIFFE way on; header names the header carrying the identity. |
gateway.config.trustedProxy.onBehalfOf.spiffePrefix | with on-behalf-of | Prefix stripped to recover the username. Pins the trust domain and the /user/ path; a value that does not start with it is refused. |
gateway.config.trustedProxy.onBehalfOf.emailDomain | with on-behalf-of | Email domain appended to the username. |
gateway.config.trustedProxy.allowedDomains | no | Restrict the accounts the proxy may create to these email domains. Empty allows any. Inert in directory mode. |
gateway.config.trustedProxy.adminEmails | no | Emails made cluster admin when the proxy creates their account, like the Single sign-on page's Admin emails. Inert in directory mode. |
gateway.config.autoProvisionUsers | no | Default true: the proxy's first sign-in for an unknown email creates the account. false is directory mode: only accounts that already exist sign in; an unknown email is refused and never created. |
When both ways are configured and a request carries both headers, on-behalf-of wins.
Asserted identity is trusted on network grounds alone. A header value
behaves like a long-lived credential for whoever it names, so the gateway must
be reachable only through the proxy; restrict ingress to it. The proxy must
also pass the browser's Origin, Referer and Sec-Fetch-Site headers
through unchanged: the gateway checks a state-changing request for cross-site
request forgery only when one of them is present.
Directory mode
With gateway.config.autoProvisionUsers: false, the proxy signs in only an account that already exists, and refuses an unknown email with a plain 401, so the proxy cannot probe who is a member. The first admin then comes from the bootstrap above, and adds the rest. For single sign-on the same choice is the Single sign-on page's New sign-ins create accounts.
Values every install sets
| Value | What it does |
|---|---|
global.publicBaseUrl | The URL people type into the address bar, https://berserk.example.com. The setup link, the single sign-on redirect URI and every absolute link are built from it. |
gateway.config.cookieSecure | true (the default) sets the Secure flag on session cookies, which needs HTTPS. Only a plain-HTTP installation on localhost sets it to false. |
global.masterKey | The key every internal credential derives from, including the one the client secret is sealed with. Chart-managed by default; see Dependencies → Master Key. |
Verifying sign-in works
curl https://<your Berserk URL>/answers303 See Otherto/login./loginshows the password form, with "Continue with SSO" above it once single sign-on is on.- Signing in sets a
__Host-sessioncookie and lands on/. bzrk loginagainst the same URL succeeds too; see Berserk CLI → Authenticating.
Security Architecture
How Berserk authenticates people, clients and its own services, and what that asks of you
Guide: Enabling Single Sign-on
Connect your identity provider to Berserk, step by step — what to register at the provider, what to enter on the Single sign-on page, and how to bring your team over