diff --git a/.claude/reference/service-catalog.md b/.claude/reference/service-catalog.md index 881ba35a..422e4ca6 100644 --- a/.claude/reference/service-catalog.md +++ b/.claude/reference/service-catalog.md @@ -96,7 +96,7 @@ | n8n | Workflow automation | n8n | | real-estate-crawler | Property crawler | real-estate-crawler | | tor-proxy | Tor proxy | tor-proxy | -| forgejo | Git forge. Open native self-signup (Turnstile captcha + email confirm) alongside Authentik OAuth; see `docs/runbooks/forgejo-open-signups.md` | forgejo | +| forgejo | Git forge. Open native self-signup (Turnstile captcha + email confirm) + Authentik & GitHub OAuth sign-in; see `docs/runbooks/forgejo-open-signups.md` | forgejo | | freshrss | RSS reader | freshrss | | navidrome | Music streaming | navidrome | | networking-toolbox | Network tools | networking-toolbox | diff --git a/docs/runbooks/forgejo-open-signups.md b/docs/runbooks/forgejo-open-signups.md index 3b206277..0637ee2c 100644 --- a/docs/runbooks/forgejo-open-signups.md +++ b/docs/runbooks/forgejo-open-signups.md @@ -10,12 +10,14 @@ layers: 2. **Mandatory email confirmation** — a new account stays inactive until the user clicks an activation link emailed to the address they registered with. -The pre-existing **Authentik OAuth2 login** ("Sign in with …") is unchanged and -still works alongside local accounts. This is additive — opening local signups -did not touch SSO. +Two external login sources also work alongside local accounts: the pre-existing +**Authentik OAuth2 login** (SSO) and **Sign in with GitHub** (see the GitHub +section below). Opening local signups was additive — it did not touch SSO. -Everything is Terraform-managed in `stacks/forgejo/`. There is no dashboard or -manual cluster state. +Most of this is Terraform-managed in `stacks/forgejo/`. The one exception is the +OAuth2 login *sources* (Authentik, GitHub), which live in Forgejo's own DB and +are added via `forgejo admin auth` — there is no clean Terraform resource for +them (their secrets are mirrored to Vault for recovery). ## What is configured (and where) @@ -33,6 +35,7 @@ env vars): | `service.CF_TURNSTILE_SECRET` | from `forgejo-turnstile` Secret | Server-side verification | | `service.REGISTER_EMAIL_CONFIRM` | `true` | Account inactive until email is confirmed | | `mailer.*` | see below | Sends the activation email | +| `oauth2_client.ENABLE_AUTO_REGISTRATION` | `true` | First GitHub (OAuth2) sign-in auto-creates the account | Captcha guards **registration only** — `REQUIRE_CAPTCHA_FOR_LOGIN` is left at the default `false`, so existing users are not captcha'd on every login. @@ -76,6 +79,42 @@ the `/user/sign_up` HTML afterwards. - The deployment carries `reloader.stakater.com/auto: "true"`, so a rotation of either secret rolls the pod automatically. +## GitHub sign-in (OAuth2 source) + +People can **sign up / sign in with GitHub** — a second Forgejo OAuth2 source +alongside Authentik. + +- **Source** (Forgejo DB, *not* Terraform — added via CLI, same as Authentik): + ``` + forgejo admin auth add-oauth --name github --provider github --key --secret + ``` + The source **name must stay `github`** — it is part of the callback URL + (`/user/oauth2/github/callback`) registered on the GitHub side, so renaming it + breaks the callback. `forgejo admin auth list` shows it (ID 2). +- **GitHub OAuth App**: a classic OAuth App under the ViktorBarzin GitHub account + (Settings → Developer settings → OAuth Apps). Homepage + `https://forgejo.viktorbarzin.me`, callback + `https://forgejo.viktorbarzin.me/user/oauth2/github/callback`. GitHub has **no + API to create OAuth Apps** — creating it is a browser-only step. +- **Credentials**: Vault `secret/viktor` → `forgejo_github_oauth_client_id` / + `forgejo_github_oauth_client_secret` (kept for recovery; the live values are in + Forgejo's DB). +- **Auto-registration**: `FORGEJO__oauth2_client__ENABLE_AUTO_REGISTRATION=true` + (`main.tf`) makes a first GitHub login create the account directly. The GitHub + identity is the trust gate for this path — the Turnstile captcha + email + confirmation only apply to the **native** signup form, not OAuth. + +**Rotate the GitHub client secret** — generate a new one in the GitHub OAuth App, then: +``` +vault kv patch secret/viktor forgejo_github_oauth_client_secret= +POD=$(kubectl -n forgejo get pod -l app=forgejo -o jsonpath='{.items[0].metadata.name}') +kubectl -n forgejo exec "$POD" -- su-exec git forgejo admin auth update-oauth --id 2 --secret +``` +(Source id from `forgejo admin auth list`.) + +**Recreate after a Forgejo DB loss**: the source is not in Terraform, so after a +from-scratch restore, re-run the `add-oauth` command above with the Vault creds. + ## Re-closing / tightening signups Edit `stacks/forgejo/main.tf` and `scripts/tg apply` (or commit + push — CI diff --git a/stacks/forgejo/main.tf b/stacks/forgejo/main.tf index 0abb1847..5e846bd6 100644 --- a/stacks/forgejo/main.tf +++ b/stacks/forgejo/main.tf @@ -280,6 +280,19 @@ resource "kubernetes_deployment" "forgejo" { } } } + # Auto-create a local account on first GitHub (OAuth2) sign-in, so + # "Sign in with GitHub" is a real sign-up path rather than a + # link-to-existing detour. The GitHub identity is the trust gate for + # this OAuth path (the Turnstile captcha + email confirmation apply to + # the native form, not OAuth). The GitHub OAuth2 source itself is added + # out-of-band via `forgejo admin auth add-oauth` (it lives in Forgejo's + # DB, not Terraform — same as the Authentik source); credentials are in + # Vault secret/viktor (forgejo_github_oauth_client_id / _secret). See + # docs/runbooks/forgejo-open-signups.md. + env { + name = "FORGEJO__oauth2_client__ENABLE_AUTO_REGISTRATION" + value = "true" + } volume_mount { name = "data" mount_path = "/data"