Manage passwords and second factors
For: cluster and tenant administrators.
Require an authenticator where needed and configure the correct client address behind a proxy.
A second step with passwords
Anyone with a password can add a second step under Settings, Account, with their current password: scan the QR code with an authenticator app (Google Authenticator, Microsoft Authenticator, 1Password, Bitwarden and others), and enter the six digits it shows. They get ten recovery codes, shown once: each signs them in once instead of the app. New recovery codes replaces them, and Turn off removes the second step, both with a code from the app.
Recovery codes are kept as a keyed, slow hash (PBKDF2 under a key derived from the master key, salted with the account's name), so a copy of the database alone cannot test a guess. Codes made before this form are changed in place to a keyed hash of their old form when the server starts (and hourly, while servers of the release before may still make them), so none stays as a plain hash; they still work, once each.
From then on, signing in asks for a code after the password. A code works once.
Wrong codes are counted for the account, from every address and on every server, whether they were sent at sign-in or on the Settings page: after ten within 15 minutes, the account's codes, recovery codes included, are refused until the 15 minutes have passed.
Each code is counted before it is checked, so codes sent all at once are held back as they would be one after another, and a right one takes back its own count; a recovery code's slow hash runs only for a counted code, and no more of them at once than the server's password checks.
Signing in with the password again does not reset the count.
The lockout is in the audit log as mfa.lockout; a cluster admin who resets the second factor (mfa reset) also ends it.
Require it
oz0 mfa require # in tenant default: its owners may
oz0 mfa require --tenant acme
oz0 mfa require --cluster # every password: cluster admins may
oz0 mfa require --tenant acme --off
oz0 mfa status # where it is required, and who has it
Owners can also turn it on for their tenants under Access, Sign-in methods.
- A tenant's policy applies to its members, and to cluster admins and readers, who see every tenant.
- Password sessions without a second step end within seconds. The next sign-in asks to set one up before it lets the person in.
- Sessions through an identity provider are not affected: the provider asks for its own second step.
Lost phone
A cluster admin removes the second step, which also signs the person out:
oz0 mfa reset kim
or with Reset second factor in the person's dialog under Access. Where a policy requires one, their next sign-in sets up a new one.
Passwords
- Your own password changes, or is removed, only with proof that you are the account's person, not only its session: the current password, and a code from your second step when you have one (Settings, Account, or
oz0 user password NAME --password-stdin --current-password-stdin --code CODE, with--removein place of--password-stdinto remove it).
Setting up a second step asks for the current password too. A cluster admin's own account is no exception; another cluster admin, or an operator's certificate, can set it. An account without a password or second step (one that signs in through a provider) cannot give itself a password this way. - Wrong passwords are counted for every management server, in the cluster's database: five within 15 minutes for one name from one address, or 30 for any names from one address (an IPv6 address counts as its /64), hold that name or address back for a minute after each further one.
Each check is counted before it runs, so passwords sent all at once, to one server or several, are held back as they would be one after another; the same goes for the current password a change of your own account asks for. A correct password clears its name's count from its address and takes back its own check, never the address's other failures. Nothing empties the count early: old failures go only once they are 15 minutes old. - A browser that signed in before is counted apart from its address. A password sign-in leaves a device cookie for that name (
__Host-oz0_device, HttpOnly, SameSite=Strict, for 180 days). Its later sign-ins to that name are counted on their own, five wrong ones then a minute after each further one, so wrong passwords others send from the same address (many people behind one proxy, or someone trying names) never hold it back. The cookie is good for its one name only, so it lets no one past the address's count for another account. - Behind a reverse proxy, name it with
--trusted-proxy(repeatable, an address or a network that only proxies hold, such as10.42.7.0/28, never the pods' whole network, where any pod could then name its own client; the Helm chart'singress.trustedProxies).
Each request from a trusted proxy is counted as the client the proxy names inX-Forwarded-For, read from the right past the trusted proxies' own entries, so a client cannot choose the address it is counted as; a request from any other address is that address's, whatever it sends.
Name the proxies alone: a client whose own address is inside a trusted network can name any address, and a server that runs management and the edge in one process trusts the list on the edge's API too, which nodes reach.
A trusted proxy's request that names no client is counted by its name alone for sign-in failures, never as the proxy's address; for unknown API keys and apps' token exchanges it is counted as the proxy's own, apart from every client the proxy names, so such requests share one allowance rather than escape the limit.
The same address goes for device sign-ins started, unknown API keys, apps' token exchanges and the sessions page.
A trusted network of every address is refused, written as 0.0.0.0/0, ::/0 or the IPv4-mapped ::ffff:0.0.0.0/96 alike.
When more addresses are held back at once than a server keeps counts for, the count used least recently makes room, so a flood from many addresses never makes the addresses after it share one count.
Without --trusted-proxy, every browser behind a proxy counts as the proxy's one address, so 30 wrong passwords through it hold back new sign-ins (from browsers that never signed in) for everyone behind it; oz0 doctor warns when management sees requests with X-Forwarded-For from a private address it does not trust.
In separate roles, an edge that lists management's addresses in its own --trusted-proxy counts the runtime API calls management hands it by their callers too.
- Unknown names, accounts without a password and wrong passwords take the same time, so the answer does not say which one it was.
- A password's stored hash is checked only with the parameters this server writes (argon2id up to 256 MiB, 10 passes and 16 lanes, or PBKDF2 up to ten million iterations); any other stored hash signs nobody in.