Replace basic auth with Microsoft 365 sign-in

nginx now checks every dashboard and API request with oauth2-proxy
(auth_request), which signs users in with Microsoft Entra ID. Who may
sign in is controlled in Entra: a single-tenant app registration with
"Assignment required", so only assigned users/groups get through.

- deploy/oauth2-proxy.cfg (entra-id provider, auth-only mode, secure
  cookie, trusted proxy = localhost) and deploy/oauth2-proxy.service
- nginx: pages redirect to Microsoft sign-in and back to the same URL;
  API calls get a plain 401 (the page already asks to reload);
  /api/v1/ingest stays key-only for collectors; /oauth2/auth is
  internal; the signed-in user is passed to the API in headers nginx
  sets (so browsers can't spoof them); dashboard files are served with
  Cache-Control: no-cache so updates show up at once
- GET /api/v1/me; the top bar shows the signed-in user and a Sign out
  that also signs out of Microsoft (otherwise SSO signs straight back in)
- README: Entra and server setup steps

Tested locally with oauth2-proxy 7.15.5 and nginx 1.31 running the
deploy configs (TLS, self-signed): redirects to the tenant's sign-in
with the return URL kept, 401s, ingest bypass, sign-out allow-list,
cookie flags, security headers. The signed-in path was tested with a
stand-in for oauth2-proxy's auth answer; a real Entra sign-in wasn't.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-08 11:31:35 -06:00
co-authored by Claude Opus 5.5
parent 8d0e6dca71
commit 2fa9eea274
13 changed files with 231 additions and 18 deletions
+46
View File
@@ -0,0 +1,46 @@
# oauth2-proxy config for Backup Dashboard's Microsoft 365 (Entra ID) sign-in.
# Install as /etc/oauth2-proxy/backup-dashboard.cfg, readable only by root and the oauth2-proxy
# user (it holds the cookie secret). Needs oauth2-proxy 7.8 or newer for the entra-id provider.
# Replace the four <...> values; see the README's "Microsoft 365 sign-in" section.
## Where it listens: only nginx talks to it
http_address = "127.0.0.1:4180"
reverse_proxy = true
# Only nginx (on this machine) may supply X-Forwarded-* headers
trusted_proxy_ips = ["127.0.0.1/32", "::1/128"]
## Entra ID app registration (single tenant)
provider = "entra-id"
oidc_issuer_url = "https://login.microsoftonline.com/<TENANT_ID>/v2.0"
client_id = "<APPLICATION_CLIENT_ID>"
# The client secret's *value*, in a file of its own, root:oauth2-proxy, mode 640
client_secret_file = "/etc/oauth2-proxy/client-secret"
redirect_url = "https://<DASHBOARD_HOST>/oauth2/callback"
## Who may sign in
# Anyone in the tenant that Entra lets through. Limit it in Entra itself: Enterprise
# applications -> this app -> Properties -> "Assignment required" = Yes, then assign users or a
# group. Entra then refuses everyone else before they ever reach the dashboard.
email_domains = ["*"]
# The user's sign-in name (UPN), which every work account has. The "email" claim is only present
# when the account has a mailbox address.
oidc_email_claim = "preferred_username"
## Session cookie
# Generate with: openssl rand -base64 32 | tr -- '+/' '-_'
cookie_secret = "<COOKIE_SECRET>"
cookie_name = "_backup_dashboard"
cookie_secure = true
cookie_samesite = "lax"
# Sign in again (usually silently, via the Microsoft session) after this long
cookie_expire = "12h"
## Behaviour with nginx's auth_request
# Auth-only: nginx serves the dashboard; oauth2-proxy just answers "signed in or not"
upstreams = ["static://202"]
# Put the user in X-Auth-Request-* headers on /oauth2/auth responses, for nginx to pass on
set_xauthrequest = true
# Go straight to Microsoft instead of showing a "Sign in with..." page first
skip_provider_button = true
# Allow "Sign out" to continue to Microsoft's sign-out page
whitelist_domains = ["login.microsoftonline.com"]