Berserk Docs

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.

AccountSigns in withComes to beManaged on
Local accountEmail and passwordThe first admin's bootstrap, or an invite from Settings → MembersSettings → Members
SSO accountYour identity provider, over OpenID ConnectAdded 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 overSettings → 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:

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:

values.yaml
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:

values.yaml
gateway:
  bootstrap:
    adminEmail: admin@example.com
    adminGivenName: Cluster
    adminFamilyName: Admin
    # adminPassword: pass it with --set, so it stays out of the file
helm 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:

values.yaml
gateway:
  bootstrap:
    adminEmail: admin@example.com
    adminGivenName: Cluster
    adminFamilyName: Admin
    existingSecret:
      name: berserk-admin
      key: bootstrap_admin_password

The 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.

SettingWhat it does
Issuer URLThe identity provider's issuer, spelled exactly as its discovery document states it, trailing slash included or not. Must be https://.
Client IDThe client registered at the provider for Berserk.
Client secretThe 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.
ScopesExtra scopes to request. openid, email and profile are always requested.
Require a verified emailRefuse 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 accountsOn: a sign-in for an unknown email creates an SSO account. Off: only members added on Settings → Members sign in through the provider.
Admin emailsEmails made cluster admin when their account is created, by SSO or by invite.
SaveStores the settings and keeps single sign-on as it is, on or off.
Enable SSO, Disable SSOTurn 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.
values.yaml
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]
ValueRequiredWhat it does
gateway.config.trustedProxy.enabledyesTurns the path on. Off by default.
gateway.config.trustedProxy.userHeaderone of the two waysHeader 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.enabledone of the two waysTurns the SPIFFE way on; header names the header carrying the identity.
gateway.config.trustedProxy.onBehalfOf.spiffePrefixwith on-behalf-ofPrefix 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.emailDomainwith on-behalf-ofEmail domain appended to the username.
gateway.config.trustedProxy.allowedDomainsnoRestrict the accounts the proxy may create to these email domains. Empty allows any. Inert in directory mode.
gateway.config.trustedProxy.adminEmailsnoEmails made cluster admin when the proxy creates their account, like the Single sign-on page's Admin emails. Inert in directory mode.
gateway.config.autoProvisionUsersnoDefault 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

ValueWhat it does
global.publicBaseUrlThe 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.cookieSecuretrue (the default) sets the Secure flag on session cookies, which needs HTTPS. Only a plain-HTTP installation on localhost sets it to false.
global.masterKeyThe 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

  1. curl https://<your Berserk URL>/ answers 303 See Other to /login.
  2. /login shows the password form, with "Continue with SSO" above it once single sign-on is on.
  3. Signing in sets a __Host-session cookie and lands on /.
  4. bzrk login against the same URL succeeds too; see Berserk CLI → Authenticating.

On this page