Skip to content

Staff access MFA plan

Status: proposal. “Verify” means we couldn’t confirm the setting from the repo or from public probes. Log in and check it.

Context

  • Staff: two people.
    • Larry: the only person with production access (AWS, Supabase, Cloudflare, Stripe, servers).
    • Laura: no production access. She does use admin.gevell.com (triage, content CMS), which is Access-gated and reads production data through the API. This deserves one sentence in the questionnaire (see Q46).
  • Posture: there’s no remote/local distinction. Internal resources are meant to be reachable only through Cloudflare Tunnels, and connections are always encrypted.
  • SSH: production SSH goes away when the office processing server is retired (#2246). The EC2 servers that replace it have no SSH; administration is through AWS Systems Manager Session Manager, behind IAM Identity Center MFA (#7). Direct LAN SSH remains only to internal hosts that hold no customer data (backups, CI runners, staging). That’s a lower-priority gap (item 6).

Inventory

#Access pathWhoCurrent auth (evidence)MFA enforced?How to enforcePriority
1Cloudflare dashboard (account c6cce84d…, also 3c71e2b8…), the root of DNS, Access, Tunnels, WAF, R2, Workers and the registrar (gevell.com and theaccessible.org both show Registrar: Cloudflare in whois)LarryEmail + password (verify)VerifyTurn on 2FA with a Touch ID passkey (WebAuthn), plus TOTP as a backup. Store the recovery codes offline. Under account Members, turn on “Enforce two-factor authentication” (verify the setting name). Remove unused members and old API tokens, and scope the remaining tokens.Must
2Cloudflare Access / Zero Trust (team anglin.cloudflareaccess.com) covering admin.gevell.com, admin-docs.gevell.com and both *.pages.dev aliasesLarry, LauraVerified gated: all four return 302 to the Access login. Login method: the README allows “Google or one-time-PIN email” (verify which is live).No, if One-time PIN is enabled, because an emailed PIN is a single factor.(a) Make Google Workspace the only IdP and remove One-time PIN. (b) Turn on Access independent MFA (GA April 2026) and require Security key or Biometrics on the admin apps’ policies. Turn on “Use IdP MFA” / AMR matching so users aren’t prompted twice. (c) Policy: include only the 2 named emails, not @gevell.com. (d) Session length ≤ 12 h.Must
3Admin API /api/admin/* (on the Lambda and Node APIs)Larry, Laura (via the admin UI)Supabase JWT + requireAdmin. Not behind Access (see waf-ruleset.md rule 11).Only as strong as the Supabase login (see #4)Route it through Access (a same-origin proxy on admin.gevell.com) and verify the Access JWT in requireAdmin. Admin actions then inherit #2’s hardware-key MFA.Must
4Supabase app login for staff admin accounts (email OTP / magic link)Larry, LauraEmail OTP (docs/admin/access/email-otp-login.md)Single factor: whoever controls the mailbox gets in. That’s acceptable only because #3 puts Access in front.Supabase Auth MFA (TOTP/WebAuthn) for is_admin users. Enforce aal2 in requireAdmin (verify plan support).Should
5Supabase dashboard (project vuvwmfxssjosfphzpzim, service-role keys, SQL editor)LarryPassword or GitHub SSO (verify)VerifyTurn on account MFA. Turn on the organization setting “Require MFA to access organization” (verify it’s on our plan). If signing in via GitHub, #9 covers it.Must
6SSH to internal LAN hosts (backups, GitHub backup, CI runners, staging). No customer data; production SSH ends with the EC2 migrationLarryKey-only via direct LAN. PasswordAuthentication status: verify.No (key only, no second factor)Put the SSH private keys in the Mac’s Secure Enclave, unlocked by Touch ID (for example the free Secretive app). The key can’t be copied off the laptop and every use needs a fingerprint, which gives a second factor without a hardware key. Set sshd: PasswordAuthentication no, PermitRootLogin no. Optionally move to Cloudflare Access for Infrastructure later.Should
7AWS IAM Identity Center portal (d-90667c73d1.awsapps.com/start, user larry)LarryPassword + MFA (docs/admin/access/aws-access.md)Yes (documented). Verify the enforcement mode.Identity Center → Settings → Authentication → MFA: “Every time they sign in (always-on)”, allowed types Security keys and built-in authenticators only (Touch ID counts as a built-in authenticator; turn off authenticator apps once two are enrolled), “If a user does not yet have a registered MFA device: Block sign-in”.Must (check)
8AWS root ([email protected]) and cdk-deployer break-glass IAM userLarryRoot: MFA, no access keys (documented). cdk-deployer: long-lived access key.Root: yes. cdk-deployer: no, because a static key bypasses MFA.Root: register a Touch ID passkey plus a backup (a second device or the optional break-glass YubiKey; AWS allows up to 8 MFA devices). cdk-deployer: deactivate the key and store it re-activatable, or attach a deny-unless-aws:MultiFactorAuthPresent policy and use it via sts get-session-token --serial-number. Also note: the github-actions-deploy OIDC role trusts repo:LarryAnglin/theaccessible-platform:* with AdministratorAccess. Narrow it to ref:refs/heads/main / environment production (not MFA, but same risk class).Must
9GitHub (LarryAnglin personal account owns theaccessible-platform; org anglinai owns @anglinai/ui packages)Larry (Laura: verify)VerifyGitHub requires 2FA for code contributors (verify on the account)Add passkeys/security keys to the account and remove SMS. Org anglinai: Settings → Authentication security → Require two-factor authentication (and “require secure methods”, if offered). Review PATs and deploy keys (runner deploy keys are read-only per mac-mini-t2-ubuntu.md).Must
10Google Workspace (gevell.com mail; IdP for Access)Larry, LauraVerifyVerifyAdmin console → Security → 2-Step Verification: Enforce for all users, with passkeys or security keys only for the admin OU (Touch ID passkeys qualify). Turn on Advanced Protection for Larry (the super admin). Keep a second super-admin break-glass account with its own keys. Because this is the IdP for #2, it’s the keystone.Must
11StripeLarryVerifyStripe requires 2-step for dashboard users (verify)Add security keys/passkeys. Keep the team at 1 admin. Use restricted API keys.Must (check)
12Resend (transactional email; API key in SSM/Workers)LarryVerifyVerifyTurn on 2FA. Check team members.Should
13Backblaze B2 (AAServerBackup, the off-site backup)LarryVerifyVerifyTurn on 2FA. Make application keys bucket-scoped. Consider Object Lock on the backup bucket (ransomware).Should
14Twilio (Voice/SMS OTP, docs/admin/access/voice-otp-setup.md)LarryVerifyVerify (Twilio has pushed 2FA by default)Turn on 2FA (Authy/TOTP or passkey). Rotate the auth token into an API key.Should
15Domain registrarLarryCloudflare Registrar (whois), so it’s covered by #1Same as #1Covered by #1. Also turn on registrar lock.(via #1)
16Grafana / Loki / Uptime KumaLarryThe repo shows only lab hostnames (grafana.test.lan, kuma.test.lan). Production exposure: verify.VerifyIf they’re reachable, publish them only as Access self-hosted apps via Tunnel (same policy as #2). Local admin passwords stay as a second layer.Should
17status.gevell.com admin API (CF Worker + D1, bearer token at ~/.config/gevell-status-admin-token)LarryStatic bearer tokenNoPut the admin paths behind Access (service token for scripts), or accept the risk (low: status data only).Nice-to-have
18Mac laptops, personally owned (the workstations that hold SSO sessions, ~/.aws, .env*, SSH keys)Larry, LauraVerifyn/aFileVault on, Touch ID + strong password, auto-lock ≤ 5 min, automatic OS updates, firewall on, Find My. .env.production.local and similar secrets live on disk, so disk encryption is the control. See ids-ips-and-threat-monitoring.md for EDR.Must (for Q47)
19Anthropic console / AWS Bedrock / other AI vendors, Apple developer, npm/GitHub Packages tokensLarryVerifyVerify2FA everywhere. Scope and expire tokens (~/.npmrc token: expiry noted in memory).Should

Phishing-resistant options and cost (estimates, verify current prices)

OptionCostWorks with
YubiKey 5 NFC (FIDO2/WebAuthn + PIV + OpenPGP)~$55 eachEverything above, including SSH PIV/FIDO2 for Access Infrastructure and ed25519-sk
YubiKey Security Key NFC (FIDO2 only)~$29 eachWebAuthn/passkeys. Not PIV, so use FIDO2 for SSH.
Platform passkeys (Touch ID / iCloud Keychain)$0Google, GitHub, AWS Identity Center (built-in authenticator), Cloudflare Access “Biometrics”, Stripe
Cloudflare Zero Trust (Access, Tunnel, Infrastructure, independent MFA)$0 (free tier ≤ 50 users)#2, #3, #6, #16

Recommendation: use the laptops’ Touch ID as the MFA device. A passkey created with Touch ID is a FIDO2 credential whose private key lives in the Mac’s Secure Enclave. It is phishing-resistant, the same standard as a hardware key. Every service in the must-do list accepts it: Google Workspace, AWS IAM Identity Center (“built-in authenticators”), Cloudflare dashboard and Access (“Biometrics”), GitHub and Stripe.

  • Backup: register a second authenticator for every account so a lost or dead laptop doesn’t lock you out. iCloud Keychain syncs passkeys to each person’s iPhone, which covers most services automatically. Also store each service’s recovery codes in the break-glass vault (#3294).
  • What protects the passkey: synced passkeys are only as safe as the Apple Account that syncs them. Protect it with its own MFA and Advanced Data Protection.
  • Hardware keys: optional. Consider one YubiKey (about $55) only for the two accounts that control everything else, the Google Workspace super admin and AWS root, stored in the break-glass kit. It is a backup that doesn’t depend on Apple, not the everyday factor. Total hardware cost: $0–110.
  • Where a service allows it, remove SMS and email as fallback factors.

Priorities

Must-do (before claiming Q46/Q47):

  1. Google Workspace 2SV enforced, passkey/security-key only for admins, Advanced Protection for Larry (#10).
  2. Cloudflare dashboard 2FA with a Touch ID passkey (#1). This also covers the registrar.
  3. Access: remove One-time PIN, Google as the only IdP, independent MFA requiring a security key or biometrics, explicit two-email policy (#2).
  4. AWS Identity Center always-on MFA with built-in authenticators (Touch ID) or security keys only; root with a Touch ID passkey plus a backup; cdk-deployer key deactivated or MFA-conditioned (#7, #8).
  5. GitHub passkeys and org 2FA requirement (#9); Supabase org MFA (#5).
  6. Admin API behind Access (#3).
  7. Mac baseline: FileVault, auto-lock, updates (#18).

Should-do: Touch ID–bound SSH keys for internal LAN hosts (#6); Stripe/Resend/Backblaze/Twilio 2FA checks (#11–14); Supabase Auth MFA for admin accounts (#4); Grafana/Kuma via Access (#16); narrow the OIDC trust (#8).

Nice-to-have: status admin via Access (#17); a written quarterly access review; an AAGUID allow-list so only approved authenticators (Apple Touch ID passkeys and any break-glass YubiKey) can enroll in Access.

Does this help the questionnaire?

  • Q46 (staff access / MFA): yes, directly. Once the must-do items are done, we can truthfully answer: “All staff access to production systems and administrative interfaces requires phishing-resistant MFA (FIDO2 passkeys bound to each laptop’s secure hardware and unlocked by biometrics) through Google Workspace, AWS IAM Identity Center and Cloudflare Access. Administrative web interfaces are reachable only through Cloudflare Access, and production servers have no SSH; administration is through AWS Systems Manager. Only one person holds production credentials. The second staff member’s access is limited to an Access-gated admin interface.” Today the HECVAT draft says “MFA on GitHub/AWS/Cloudflare/Supabase/Stripe” but its own checklist item 6 says to confirm it. Until the checks above are done, the claim isn’t evidence-backed.
  • Q47 (remote workstation security): partly. MFA and Access/Tunnel cover how staff connect. Q47 also asks about the endpoint itself: disk encryption, patching, screen lock and anti-malware/EDR. Item #18 and the EDR recommendation in ids-ips-and-threat-monitoring.md complete the answer. Because we have no remote/local distinction, the honest answer is that every workstation meets the “remote” standard at all times.