Skip to main content
Version: Next

Users, groups and roles

Fadebox has two kinds of role. Global roles are platform-wide and live on the user account. Project roles apply inside one project and are granted through groups.

Global roles​

TeamEnterprise

Free covers five people — only active accounts count, so deactivating one frees a seat. See Licensing.

RoleWhat it allows
userThe baseline every account has. On its own it grants no access to any project — you see only what a project role gives you.
template_adminCreate, edit and delete templates, start template test runs, import catalog entries, and administer catalog sources — global ones and any project's.
adminEverything. Manages users, groups, identity providers and runtimes; creates and deletes projects; decides per project whether unsafe template configuration is allowed; and bypasses project roles — an admin has full authority in every project.

Admins assign global roles under Users. New accounts — including those auto-provisioned by an OIDC provider — start as user.

Project roles​

Inside a project the roles are hierarchical: maintainer ⊃ editor ⊃ deployer ⊃ viewer. Holding maintainer implies everything editor may do, which implies everything deployer may do, which implies everything viewer may do.

viewerdeployereditormaintainer
See the project, its environments and instances●●●●
Open a gated instance's URLs — at Members any of them; at Creator the ones they created●●●●
Read repositories and registry entries●●●●
Create instances; deploy, stop, extend and delete shared ones and their own●●●
Reset an instance — containers, network and volumes●●●
Raise the gate on an instance's URLs — shared ones and their own●●●
Set values on services the environment opened to deployers●●●
Say what an instance is for, report checks on it, and approve or reject what it runs●●●
Mint an access token for a gated instance's URLs they may open●●●
Remove images only this project's instances pulled and nothing wants●●●
Read instance status and logs●●●●
Create, edit, clone and delete environments — services, waves, image tags, shared variables, files●●
Decide which services deployers may vary, and in what●●
Operate a colleague's personal instance, and share or unshare any instance●●
Open any instance gated to Creator, lower any instance's gate, and create an instance below its environment's default level●●
Edit or delete a protected environment; protect and unprotect one●
Manage git repositories and registry credentials●
Manage members and API keys●
Register, sync, switch and remove the project's own catalog sources●
Import catalog entries into the project, and create, edit and delete the project's own templates●

The line the two upper rungs draw is between doing the work and holding the keys. An editor composes: services, waves, image tags, shared variables, injected files, the blueprint flag. A maintainer also administers: who is in the project, its git and registry credentials, its catalog sources and templates, its API keys, its audit slice. Handing someone editor is therefore not a step towards handing them the credential store.

Creating a project is a global-admin act — you cannot be a member of a project that does not exist yet. The admin who creates one is seeded into its maintainers, so they can run it afterwards without using their global role.

What you can see follows the same line. The runtime list is narrowed to what you could actually deploy onto: a global admin sees every runtime, and everyone else sees those any of their own projects may use. A runtime row names a Docker daemon's address and the projects granted it, so an unnarrowed list would hand both to someone with no project at all. The daemon address's neighbours — the project allow-list and the ACME contact — are admin-only fields and come back empty for everyone else, on a row they can otherwise see.

Who gets which role​

The roles are named after what they let you do, never after a job — the same four rungs have to serve a software team, a sales engineer's demo stacks and a trainer's labs. The translation:

The personThe role, and why
Platform or DevOps engineer running the installationGlobal admin, and template_admin for whoever curates the catalog. Runtimes, identity providers, users and projects are platform-wide, so they are not a project role at all.
Tech lead or engineering manager who owns the projectmaintainer. They decide who is in it, which repositories and registries it uses, and which of its environments are protected.
Developereditor. "Run my branch against the rest" is an image tag, and adding a WireMock is a service — both are composing. They never see the member list or the credential store.
QA or testereditor. The same, plus keeping named stacks like regression and uat configured.
Release managereditor on the projects whose staging and uat they move — or maintainer, if those environments are protected and you have decided that moving them is an administrative act.
Support engineer reproducing a customer's bugeditor. Versions live on the environment, so "the same stack on 1.3.2" means cloning it and setting the tag on the copy, which is an editor's to do.
Sales engineer, pre-saleseditor. One demo stack per prospect, with the prospect's data image and branding.
Trainer or educatoreditor. A lab per attendee, cloned from a base and varied per course.
Data or ML engineereditor. A test bed pinned to one dataset or model version — again an image tag on an environment of their own.
Product owner, designer, salespersondeployer. They bring the demo stack up, open its URL and show it; they never change what it is. Their copy is personal by default: colleagues see it, and only they and the editors can stop it.
Stakeholder, reviewerviewer, which is also what opens an instance gated to the project's members. A colleague who only needs to open a project's instance URLs needs no more than this.
CI pipeline deploying a per-pull-request instancedeployer. It deploys an environment somebody else defined. Its instances are personal to the service account unless the environment says new instances are shared — turn that on for the per-PR environment, or a cleanup job under another account needs editor.
A pipeline that writes definitions — pinning a build's image tags on the environment, or syncing environment definitions from a repositoryeditor. Writing a definition was never a deployer right, and maintainer would hand the pipeline your credentials and the ability to mint API keys.
Contractor or partnerWhichever of the above their work is, granted through a group scoped to the one project — see groups.
Compliance or security reviewerReading the audit log is not a role of its own: the project's own slice is a maintainer read, and the platform-wide log an admin one.

Two of these are worth stating as rules rather than rows. A pipeline gets the role its job needs and no more — deploying and defining are different jobs, and most pipelines only deploy. Nobody needs maintainer in order to build things; if someone is asking for it so they can change a stack, editor is the answer.

Protected environments​

An environment can be marked protected, which narrows composing on that one environment back to a maintainer. It is what makes editor safe to hand out widely: everyone can build their own stacks while the shared staging stays in a few hands, instead of the whole team being kept off the composer to protect one environment.

An editor's writes to a protected environment — services, waves, image tags, shared variables, injected files, and deleting it — are refused with 403 and a message naming the flag. Raising and lowering the flag is a maintainer's act, in both directions.

Two things protection deliberately leaves alone. An editor may still clone a protected environment, and the clone is not protected — copying staging and retagging the copy is the daily path, and protection guards the original without withholding what is in it. And instances are untouched: deploying, stopping, extending and deleting instances of a protected environment stay a deployer right, because protection says who may change what the environment is, not whether it may run. See protected environments for the flag itself.

Groups are how project roles are granted​

A group is a set of people. What a group grants is a set of edges of the form "every member of this group holds role in project". Users are never granted a project role directly — the grant always runs through a group, which is what makes an org-wide directory usable as the source of truth.

Membership comes from one of two places:

  • Manual — an admin adds the user to the group.
  • A claim mapping — an OIDC sign-in whose group claim carried a value the group maps.

Two ways to work with the same machinery​

From the project — Project → Settings → Members. The table lists each person once, with every role they hold here and the group each role comes from, and a search box narrows it by username or email (since 1.1.2). A maintainer starts typing a name, email or group and picks from the matches, then chooses a role — no need to know a username or a group slug by heart. The search runs on the server and reaches accounts and groups that are not in the project yet, which is why it is a maintainer's to use rather than any member's. Behind the scenes the member is added to one of the project's project groups, and you never have to think about groups to run a project. Rows that came from a shared org group or from an SSO sync appear here read-only — revoking them belongs where they were granted.

Every project is born with one project group per role — acme-viewers, acme-deployers, acme-editors and acme-maintainers for a project acme — each granting exactly that role there. They appear under Access → Groups with a Project group badge. A project group is created with its project and deleted with it; it cannot be deleted by hand, and its one grant is fixed. Everything else works as for any group: an admin can add members to it directly, and can attach a claim mapping to it, which is the shortest route from a directory group to a project role (see below). Because the names belong to the project, creating a group of your own under a project-group name is refused, and creating a project whose group names a hand-made group already holds is refused with a message naming the group — rename or delete it first. On upgrade, projects that predate this gain their missing project groups at startup; a project whose name a hand-made group holds is skipped and logged.

From the platform — Access → Groups, as an admin. This is where you create groups that span projects (platform-team, qa), give them roles in several projects at once, and attach claim mappings — to those groups, or to a project group when a directory group maps onto one role in one project.

Passwords​

The sign-in form takes an account's username, or its email address when exactly one active account has that address; a value that is some account's username always means that account. An address two active accounts share signs in neither of them — it is refused exactly as an unknown name is — so those accounts sign in by username.

A password is compared as typed, after one normalization: Unicode NFC, so an accented letter typed as one character or as a letter plus a combining accent is the same letter. Nothing else is folded — a superscript ², a µ or a fullwidth letter is its own character, not the plain one it looks like.

:::note Passwords set on 1.4.0 or earlier Until 1.4.1 passwords were stored under a normalization that also folded such characters into their plain forms. A password set then that contains one of them — ², µ, º, or the fullwidth letters some input methods type — no longer signs in, and failed attempts count towards the lockout. An administrator resets it: edit the account under Users and type a new password, which is temporary like any other the holder did not choose (below). Plain ASCII and ordinary accented letters (ö, é) are unaffected, and so are single sign-on accounts and API keys. :::

A password the account holder did not choose is temporary. That covers the generated bootstrap password, an account an admin creates with a password typed into the form, and an admin resetting somebody's password. Until it is replaced, the account can reach exactly one thing — the password form — and everything else answers 403; the create-user form says as much, so an admin knows what they are handing over.

Replacing it needs the current password, and clearing the flag frees the session already open, so nobody has to sign in twice. A user who cannot produce the current password can still sign out from that screen rather than being stuck on a dead session.

Changing your own password lives at Settings → Account. It appears only for accounts that have a password here at all: a federated user's credentials belong to their identity provider, and a service account has none, so both see a sentence saying where the credential lives instead of a form that could not work.

An account locked this way also cannot authenticate with an API key, and cannot create one — which makes forcing a reset a way to contain an account without deleting it.

Guessing is expensive​

The sign-in page is usually on the same host as the instance URLs a team hands round, so it is the one credential check a stranger can reach. Two limits make a guess cost something, and neither of them tells the guesser anything.

Five wrong passwords in a row lock the account for a minute. The count is per account and consecutive — a mistyped password or a stale entry in a password manager does not get near it — and a successful sign-in clears it. The lock is flat and every lock costs a fresh five failures: a scheme that escalated would let someone who knows only a username hold the account shut with one cheap request an hour, and the bootstrap makes admin a username everybody knows. What that leaves is honest: an attacker who keeps failing five times a minute keeps the account shut for as long as they keep paying that, loudly, from an address the audit log records.

A locked account answers exactly as a wrong password does — the same page, the same status, the same delay — because a message saying locked confirms to the guesser that the account exists and is being attacked, and hands them a schedule. The audit log is where the difference is written: user.login_locked once when the lock engages, with the failure count and the deadline, and the refused attempts as failed sign-ins with the reason locked. That is the intended path for the person who mistyped: the admin sees it, and tells them. A lock expires by itself; an admin clears it early by resetting the account's password or by reactivating a deactivated account — the two things an admin already does for an account in trouble — and either shows up as unlocked in the user.updated event.

Ten failed credentials from one address, refilled ten a minute. The lock is per account and misses two shapes — one password sprayed across many usernames, which never fails five times on any single account, and guessed API keys or agent tokens, which have no account to lock until the credential resolves. So every failed credential check, at every door, spends one token from a bucket per client address; an empty bucket refuses the next attempt from that address before any lookup, again indistinguishably. Only a credential that failed to verify spends a token: a key that verified and was then refused — expired, revoked, a deactivated account — spends nothing, so an automation retrying a key it forgot to rotate cannot lock out its neighbours. The bucket is per node and forgotten on a restart, which costs an attacker one more burst and nobody anything else.

Behind a reverse proxy that address is the proxy's own until QUARKUS_HTTP_PROXY_TRUSTED_PROXIES says which peers may speak for a client — a forwarded address anyone can write is not something to rate-limit on — so until it is set every client shares one bucket. Both limits are configurable, and both leave single sign-on alone: a federated account's credentials, and the policy for guessing them, belong to the identity provider.

Sessions​

A signed-in session expires when it is idle for thirty minutes, whichever way it was signed in. Any request slides the window forward, so somebody working is never interrupted, while a tab left open overnight is signed out.

  • Form sign-in. The session lives in an encrypted cookie, and the browser stops presenting it at exactly the moment the server stops accepting it — so an idle tab comes back to the sign-in page rather than to a 401 on a cookie the server had already written off.
  • Single sign-on. The same window, held by renewing with the provider behind the scenes. The session is no longer capped at the life-span of the provider's ID token, which is what used to sign everyone out every few minutes behind a provider issuing the customary five-minute one. Renewal happens on a request rather than on a clock, so the window measured from a user's last request runs from thirty minutes to thirty minutes plus one token life-span — an approximation of the form side, not a match.
  • The identity provider has the last word. Its own policy — Keycloak's SSO Session Idle, for instance — is a ceiling Fadebox cannot raise: once the provider stops honouring the renewal, the session is over. That dial belongs at the provider.

"Idle" means no HTTP request, not nobody at the keyboard. A page that polls — an environment page watching instances come up — renews the session for as long as it is open.

The form side's window is configurable; the SSO side is fixed at thirty minutes, so an installation that lengthens the form window lengthens only that one.

An API key is not a session and never idles out. It lives until it expires or is revoked.

Mapping identity-provider groups​

Enterprise

A claim mapping puts everyone whose token carries a given value into a Fadebox group. Attaching claim mappings is an Enterprise feature; everything else on this page — groups, project roles, manual membership — is available on every tier.

A mapping always names which provider asserted the value. This matters: a bare claim value would be global, so engineering emitted by a contractor's directory would land in the same group as engineering from your corporate one — and that group carries project role grants. Scoping the match to the provider the token was verified against means an outside directory administrator cannot mint membership in your groups.

A group with no claim mappings can only be filled by hand. A project group takes a mapping like any other group: map your directory's acme-developers onto acme-deployers and its members hold deployer in acme on their next sign-in, with nothing else to set up. A directory group that should hold roles in several projects maps onto a regular group with a grant per project instead — a claim value maps to exactly one group. The invariant throughout: a claim can only place you in a group an admin defined, and only an admin decides what that group grants.

note

Group membership from a sign-in is recomputed on each request of a signed-in SSO user, so removing someone from a directory group takes effect on their next request — you do not have to wait for a session to expire.

Service accounts​

TeamEnterprise

Free covers three service accounts, an allowance separate from the one for people. See Licensing.

CI pipelines authenticate as service accounts: accounts with roles and memberships like anyone else, but with no password and no interactive sign-in. They hold API keys instead.

A key is not only a service-account thing: you can issue one for your own account too, and it carries exactly your roles and projects. Only you can create or revoke it — see Your own keys.