forgejo: open native self-signups, gated by Turnstile + email confirmation
All checks were successful
ci/woodpecker/push/default Pipeline was successful
All checks were successful
ci/woodpecker/push/default Pipeline was successful
Viktor wants Forgejo open for anyone to sign up, but without bot/spam
account floods. Flip the deployment from OAuth-only registration
(ALLOW_ONLY_EXTERNAL_REGISTRATION=true) to allowing native local
sign-up, and add two bot gates on the registration form:
- Cloudflare Turnstile captcha (CAPTCHA_TYPE=cfturnstile). The widget
is managed in Terraform (turnstile.tf) via the CF Global API key, so
the sitekey/secret are IaC, not a dashboard artifact.
- Mandatory email confirmation (REGISTER_EMAIL_CONFIRM=true). Wire the
Forgejo mailer to the cluster mailserver as noreply@viktorbarzin.me
(mail.viktorbarzin.me:587 STARTTLS), reusing the same Vault-sourced
credential Authentik uses (email-secret.tf ESO -> secret/authentik
smtp_password).
Existing Authentik OAuth2 login is unchanged (additive). Deployment env
appended (not inserted) so the diff stays purely additive; a reloader
annotation rolls the pod on secret rotation.
Verified live: signup page renders the Turnstile widget, mailer delivers
a test message end-to-end, Forgejo healthy, plan-to-zero after apply.
Runbook: docs/runbooks/forgejo-open-signups.md
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
21dbd79ae4
commit
963e4fcdde
5 changed files with 292 additions and 3 deletions
|
|
@ -92,8 +92,16 @@ resource "kubernetes_deployment" "forgejo" {
|
|||
# from 11.0.14 → 1.18 on 2026-05-24 (same bug as memory id=1933).
|
||||
# TF owns the tag now; bump it manually here when upgrading.
|
||||
"keel.sh/policy" = "never"
|
||||
# Roll the pod when the signup secrets (forgejo-email password from Vault,
|
||||
# forgejo-turnstile secret) change — env vars are read at boot, not
|
||||
# hot-reloaded. Stakater Reloader watches all referenced secrets/CMs.
|
||||
"reloader.stakater.com/auto" = "true"
|
||||
}
|
||||
}
|
||||
# The forgejo-email Secret is materialised by the External Secrets operator
|
||||
# from the forgejo-email ExternalSecret (email-secret.tf); ensure the CR
|
||||
# exists before this deployment references it on a from-scratch apply.
|
||||
depends_on = [kubernetes_manifest.forgejo_email_secret]
|
||||
spec {
|
||||
replicas = 1
|
||||
strategy {
|
||||
|
|
@ -142,14 +150,21 @@ resource "kubernetes_deployment" "forgejo" {
|
|||
name = "FORGEJO__server__ROOT_URL"
|
||||
value = "https://forgejo.viktorbarzin.me"
|
||||
}
|
||||
# Disable local registration — only allow OAuth2 (Authentik)
|
||||
# Open self-service registration. Native local sign-up is allowed
|
||||
# (ALLOW_ONLY_EXTERNAL_REGISTRATION=false) alongside the existing
|
||||
# Authentik OAuth2 login. Bot abuse is gated by Cloudflare Turnstile
|
||||
# (ENABLE_CAPTCHA below) + mandatory email confirmation
|
||||
# (REGISTER_EMAIL_CONFIRM below). To re-close signups: set
|
||||
# DISABLE_REGISTRATION=true, or flip ALLOW_ONLY_EXTERNAL_REGISTRATION
|
||||
# back to "true" for OAuth-only. Runbook:
|
||||
# docs/runbooks/forgejo-open-signups.md
|
||||
env {
|
||||
name = "FORGEJO__service__DISABLE_REGISTRATION"
|
||||
value = "false"
|
||||
}
|
||||
env {
|
||||
name = "FORGEJO__service__ALLOW_ONLY_EXTERNAL_REGISTRATION"
|
||||
value = "true"
|
||||
value = "false"
|
||||
}
|
||||
env {
|
||||
name = "FORGEJO__openid__ENABLE_OPENID_SIGNIN"
|
||||
|
|
@ -190,6 +205,81 @@ resource "kubernetes_deployment" "forgejo" {
|
|||
name = "FORGEJO__repository__DISABLE_DOWNLOAD_SOURCE_ARCHIVES"
|
||||
value = "true"
|
||||
}
|
||||
# --- Open-signup bot prevention + mailer (appended so the diff vs the
|
||||
# pre-signup deployment stays purely additive). ---
|
||||
# Cloudflare Turnstile captcha on the registration form (widget
|
||||
# managed in turnstile.tf). Sitekey is public (rendered in the page);
|
||||
# the secret is injected from the forgejo-turnstile Secret. Guards
|
||||
# registration only — not every login (REQUIRE_CAPTCHA_FOR_LOGIN left
|
||||
# at the default false).
|
||||
env {
|
||||
name = "FORGEJO__service__ENABLE_CAPTCHA"
|
||||
value = "true"
|
||||
}
|
||||
env {
|
||||
name = "FORGEJO__service__CAPTCHA_TYPE"
|
||||
value = "cfturnstile"
|
||||
}
|
||||
env {
|
||||
name = "FORGEJO__service__CF_TURNSTILE_SITEKEY"
|
||||
value = cloudflare_turnstile_widget.forgejo_signup.id
|
||||
}
|
||||
env {
|
||||
name = "FORGEJO__service__CF_TURNSTILE_SECRET"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
name = kubernetes_secret.forgejo_turnstile.metadata[0].name
|
||||
key = "cf-turnstile-secret"
|
||||
}
|
||||
}
|
||||
}
|
||||
# Mandatory email confirmation: new accounts stay inactive until the
|
||||
# user clicks an emailed activation link (kills throwaway-email bots).
|
||||
env {
|
||||
name = "FORGEJO__service__REGISTER_EMAIL_CONFIRM"
|
||||
value = "true"
|
||||
}
|
||||
# Mailer: reuse the noreply@viktorbarzin.me mailserver SASL account
|
||||
# (same as Authentik). MUST use the public host mail.viktorbarzin.me,
|
||||
# NOT mailserver.mailserver.svc — the mailserver serves the
|
||||
# *.viktorbarzin.me wildcard cert which does not cover the svc DNS
|
||||
# name, so STARTTLS verification would fail. mail.viktorbarzin.me
|
||||
# resolves in-cluster (10.0.20.1) and matches the cert. Password from
|
||||
# the forgejo-email ESO Secret (Vault secret/authentik ->
|
||||
# smtp_password; see email-secret.tf).
|
||||
env {
|
||||
name = "FORGEJO__mailer__ENABLED"
|
||||
value = "true"
|
||||
}
|
||||
env {
|
||||
name = "FORGEJO__mailer__PROTOCOL"
|
||||
value = "smtp+starttls"
|
||||
}
|
||||
env {
|
||||
name = "FORGEJO__mailer__SMTP_ADDR"
|
||||
value = "mail.viktorbarzin.me"
|
||||
}
|
||||
env {
|
||||
name = "FORGEJO__mailer__SMTP_PORT"
|
||||
value = "587"
|
||||
}
|
||||
env {
|
||||
name = "FORGEJO__mailer__FROM"
|
||||
value = "Forgejo <noreply@viktorbarzin.me>"
|
||||
}
|
||||
env {
|
||||
name = "FORGEJO__mailer__USER"
|
||||
value = "noreply@viktorbarzin.me"
|
||||
}
|
||||
env {
|
||||
name = "FORGEJO__mailer__PASSWD"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
name = "forgejo-email"
|
||||
key = "PASSWD"
|
||||
}
|
||||
}
|
||||
}
|
||||
volume_mount {
|
||||
name = "data"
|
||||
mount_path = "/data"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue