For Divvent’s own team. It is generated from the operations document in our repository, which is the one to edit. If you use Divvent, the help centre is for you.
6f. Break-glass's second factor: what Access must require — BY HAND
Break-glass (§4) needs a second factor, and the console cannot see one: an operator reaches it through Cloudflare Access, and Access's application token says nothing about how somebody signed in. It carries aud, email, exp, iat, nbf, iss, type, identity_nonce, sub and country — no amr, no authentication method, no identity provider (Cloudflare: application token). What it does carry, signed, is iat: when Access issued it, which is when the operator last passed the console application's policy.
So the proof is two halves, and the console holds only one:
- The console holds the clock.
requestBreakGlassrefuses unless the verified assertion'siatis within ten minutes (BREAK_GLASS_FRESH_MSinpackages/control/src/breakglass.ts), and refuses an assertion without one. That is built and tested. - Access holds the factor. A recent
iatmeans a recent second factor only if Access demanded one at that sign-in. That is the setting below, and without it break-glass needs only a recent Google sign-in.
The stronger option — reading the factor off the token — is not one Cloudflare offers: Access's Authentication method rule (Require → mfa) makes Access refuse a sign-in without MFA, but it is available only for Okta, Microsoft Entra ID, generic OIDC and generic SAML, not the Google Workspace provider the console uses, and it still adds nothing to the token (Cloudflare: enforce MFA). Access's independent MFA works with any provider, and is what to set.
In the Cloudflare dashboard of the account that holds the console (staging's, and production's at §9.1), by somebody who can edit Zero Trust:
- Zero Trust → Access controls → Access settings → Allow multi-factor authentication (MFA): select the methods to allow (Security key, Biometrics, and Authenticator application if any operator has no key) and save. Cloudflare refuses an application-level setting until this is on (Cloudflare: independent MFA). Leave Apply global MFA settings by default off unless you want it on every application; the rule this needs is the console's.
- Zero Trust → Access controls → Applications → "Divvent console" → Configure → Authentication → MFA: choose Custom MFA settings; allow Security keys and Biometrics (and Authenticator application if any operator has no key); set Authentication duration to Require every login. Save. On staging, do the same for "Divvent preview consoles".
- Set it on the application, not the policy. The deployer rewrites the operator policy (
operators running WARP) on every deploy with aPUTof its whole body, so an MFA setting on the policy would be erased by the next push. It never updates an application that exists, so the application's setting stays. - Check it: open
/cdn-cgi/access/logouton the console, then the console again. Access must ask for the second factor before it lets you in. Then open Break-glass: the page says "You signed in to the console 0 minutes ago"; reload a few minutes later and it must say a larger number. (TheCf-Access-Jwt-Assertionheader carries the same token as theCF_Authorizationcookie, so it should — Cloudflare: validate JWTs.) - Check a silent reissue asks for the factor too. Access keeps two sessions: the application token on the console's host, and a global session on the team domain. "When the application token expires, Cloudflare will automatically issue a new application token if the global token is still valid", with a new
iat— and Cloudflare does not say whether independent MFA is asked again when it does (Cloudflare: session management). So: sign in to the console; in the browser's developer tools delete only theCF_Authorizationcookie on the console's host (not the one ondivvent.cloudflareaccess.com); reload.- Access asks for the second factor: done. A fresh
iatmeans a fresh factor, and break-glass's bound is "within ten minutes". - Access lets you straight back in: a reissue skips the factor, so a fresh
iatmeans only "the global session is still live", and the factor behind it can be as old as that session. Then shorten the global session: Zero Trust → Access controls → Access settings → Set your global session duration → Edit → the shortest it offers (15 minutes) → Save (same page). Break-glass's bound is then honestly "a second factor within the global session — at most 15 minutes, plus the ten" rather than "within ten minutes", and the page's "signed in N minutes ago" means Access's last policy check, not the last factor. Tell whoever is on the code, so SECURITY §12 and DESIGN §10 say which. Setting the global session to 15 minutes means operators sign in to Access, factor and all, at least that often; the console application's ownsessionDuration(8h ininfra/control-plane.json) no longer decides how often.
- Access asks for the second factor: done. A fresh
- Check the scheduler still gets in. Its Service Auth policy admits a service token, which no MFA prompt applies to; its next pass should still complete (
divvent doctor --requireon the next staging deploy).
Using it: an operator whose sign-in is older than ten minutes is refused — to ask for a grant or to approve one — with a sentence saying so and a link to /cdn-cgi/access/logout. That link ends the global session as well as the console's ("all previously issued tokens will stop being accepted in 20-30 seconds", session management), so the sign-in after it is a full one. Sign out, sign in (Access asks for the factor), and ask or approve within ten minutes.