Expose Forgejo publicly at forge.eblu.me (#278)
All checks were successful
Deploy Fly.io Proxy / deploy (push) Successful in 1m28s
All checks were successful
Deploy Fly.io Proxy / deploy (push) Successful in 1m28s
## Summary Expose Forgejo publicly at `forge.eblu.me` via the Fly.io reverse proxy — the first dynamic, authenticated public-facing service. - **Forgejo hardening:** Domain changed to forge.eblu.me, SSH stays on forge.ops.eblu.me, reverse proxy trust headers configured, local registration locked to external-only (Authentik SSO) - **Tailscale Ingress:** ExternalName Service + Ingress in tailscale-operator creates forge.tail8d86e.ts.net endpoint - **Fly.io proxy:** nginx server block with rate-limited auth endpoints (3r/s), fail2ban with custom nginx-deny action, security headers, /swagger blocked, WebSocket support, 512m body limit - **Authentik:** OAuth callback updated to forge.eblu.me - **DNS/TLS:** CNAME record in Pulumi, cert in fly-setup - **Rename:** ~29 files updated from forge.ops.eblu.me to forge.eblu.me (HTTPS refs only; SSH, container builds, and Caddy table kept as-is) ## Deployment Order 1. `mise run provision-indri -- --tags forgejo` (config changes) 2. Verify forge.ops.eblu.me still works 3. `argocd app set tailscale-operator --revision feature/forge-public && argocd app sync tailscale-operator` 4. Verify `curl https://forge.tail8d86e.ts.net` 5. `cd fly && fly deploy` 6. Verify pre-DNS: `curl -H "Host: forge.eblu.me" https://blumeops-proxy.fly.dev/` 7. `fly certs add forge.eblu.me -a blumeops-proxy` 8. `argocd app set authentik --revision feature/forge-public && argocd app sync authentik` 9. `mise run dns-preview && mise run dns-up` 10. Full verification (see below) 11. Rehearse `mise run fly-shutoff` 12. After merge: reset ArgoCD revisions to main, re-sync ## Verification Checklist - [ ] forge.eblu.me loads, shows public repos - [ ] forge.ops.eblu.me still works from tailnet - [ ] SSH clone via forge.ops.eblu.me:2222 works - [ ] HTTPS clone via forge.eblu.me works - [ ] UI shows forge.eblu.me for HTTPS clone, forge.ops.eblu.me for SSH - [ ] /swagger returns 403 - [ ] Rapid login attempts trigger 429 rate limit - [ ] fail2ban bans after 5 failed logins in 10 minutes - [ ] ArgoCD can still sync (SSH unaffected) - [ ] `mise run fly-shutoff` stops all public traffic - [ ] `mise run services-check` passes Reviewed-on: #278
This commit is contained in:
parent
a32c99a252
commit
a87c997ee1
49 changed files with 340 additions and 128 deletions
|
|
@ -6,7 +6,7 @@ metadata:
|
|||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://forge.ops.eblu.me/eblume/blumeops.git
|
||||
repoURL: https://forge.eblu.me/eblume/blumeops.git
|
||||
targetRevision: main
|
||||
path: argocd/manifests/forgejo-runner
|
||||
destination:
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ data:
|
|||
client_secret: !Env AUTHENTIK_FORGEJO_CLIENT_SECRET
|
||||
redirect_uris:
|
||||
- matching_mode: strict
|
||||
url: https://forge.ops.eblu.me/user/oauth2/authentik/callback
|
||||
url: https://forge.eblu.me/user/oauth2/authentik/callback
|
||||
signing_key: !Find [authentik_crypto.certificatekeypair, [name, authentik Self-signed Certificate]]
|
||||
property_mappings:
|
||||
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]]
|
||||
|
|
@ -138,7 +138,7 @@ data:
|
|||
name: Forgejo
|
||||
slug: forgejo
|
||||
provider: !KeyOf forgejo-provider
|
||||
meta_launch_url: https://forge.ops.eblu.me
|
||||
meta_launch_url: https://forge.eblu.me
|
||||
policy_engine_mode: any
|
||||
|
||||
# Policy binding — restrict Forgejo to admins group
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ spec:
|
|||
name: http
|
||||
env:
|
||||
- name: CV_RELEASE_URL
|
||||
value: "https://forge.ops.eblu.me/api/packages/eblume/generic/cv/v1.0.3/cv-v1.0.3.tar.gz"
|
||||
value: "https://forge.eblu.me/api/packages/eblume/generic/cv/v1.0.3/cv-v1.0.3.tar.gz"
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ spec:
|
|||
name: http
|
||||
env:
|
||||
- name: DOCS_RELEASE_URL
|
||||
value: "https://forge.ops.eblu.me/eblume/blumeops/releases/download/v1.12.1/docs-v1.12.1.tar.gz"
|
||||
value: "https://forge.eblu.me/eblume/blumeops/releases/download/v1.12.1/docs-v1.12.1.tar.gz"
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ spec:
|
|||
- name: DOCKER_HOST
|
||||
value: tcp://localhost:2375
|
||||
- name: FORGEJO_URL
|
||||
value: "https://forge.ops.eblu.me"
|
||||
value: "https://forge.eblu.me"
|
||||
- name: RUNNER_NAME
|
||||
value: "k8s-runner"
|
||||
- name: RUNNER_LABELS
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
- Host Services:
|
||||
- Forgejo:
|
||||
href: https://forge.ops.eblu.me
|
||||
href: https://forge.eblu.me
|
||||
icon: forgejo
|
||||
description: Git forge
|
||||
widget:
|
||||
type: gitea
|
||||
url: https://forge.ops.eblu.me
|
||||
url: https://forge.eblu.me
|
||||
key: "{{HOMEPAGE_VAR_FORGEJO_API_KEY}}"
|
||||
- Registry:
|
||||
href: https://registry.ops.eblu.me
|
||||
|
|
|
|||
|
|
@ -73,7 +73,6 @@ kubectl logs -n tailscale -l app.kubernetes.io/name=operator
|
|||
| `operator.yaml` | Operator deployment, CRDs, RBAC (secret removed) |
|
||||
| `proxyclass.yaml` | ProxyClass with fully-qualified images |
|
||||
| `dnsconfig.yaml` | DNSConfig for cluster-to-tailnet name resolution |
|
||||
| `egress-forge.yaml` | Egress proxy for accessing forge on indri |
|
||||
| `secret.yaml.tpl` | 1Password template for OAuth credentials (manual) |
|
||||
| `README.md` | This file |
|
||||
|
||||
|
|
@ -86,5 +85,3 @@ kubectl logs -n tailscale -l app.kubernetes.io/name=operator
|
|||
annotations:
|
||||
tailscale.com/proxy-class: "default"
|
||||
```
|
||||
- The egress proxy for forge is **deprecated**. Forge is now accessible via Caddy at
|
||||
`forge.ops.eblu.me` (HTTPS) and `forge.ops.eblu.me:2222` (SSH), which pods can reach directly.
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
# DEPRECATED: This egress proxy is no longer needed.
|
||||
# Forge is now accessible via Caddy at forge.ops.eblu.me (HTTPS) and
|
||||
# forge.ops.eblu.me:2222 (SSH), which pods can reach directly.
|
||||
#
|
||||
# Keeping this file for reference during migration. Remove once verified.
|
||||
#
|
||||
# Original purpose: Egress proxy to expose Forgejo (forge) to the cluster
|
||||
# See: https://tailscale.com/kb/1438/kubernetes-operator-cluster-egress
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: forge
|
||||
namespace: tailscale
|
||||
annotations:
|
||||
tailscale.com/tailnet-fqdn: indri.tail8d86e.ts.net
|
||||
tailscale.com/proxy-class: "default"
|
||||
spec:
|
||||
type: ExternalName
|
||||
externalName: placeholder
|
||||
ports:
|
||||
- port: 3001
|
||||
targetPort: 3001
|
||||
24
argocd/manifests/tailscale-operator/endpoints-forge.yaml
Normal file
24
argocd/manifests/tailscale-operator/endpoints-forge.yaml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
# Manual Endpoints pointing to indri's Tailscale IP for the
|
||||
# forge-external Service. Must match the Service name exactly.
|
||||
#
|
||||
# NOTE: ArgoCD excludes all Endpoints resources (resource.exclusions in
|
||||
# argocd-cm) because they are normally auto-managed by the control plane.
|
||||
# This manual Endpoints is the exception — it must be applied directly
|
||||
# with kubectl, not via ArgoCD. It is listed in kustomization.yaml for
|
||||
# documentation purposes only; ArgoCD will silently skip it.
|
||||
#
|
||||
# kubectl --context=minikube-indri apply -f endpoints-forge.yaml
|
||||
#
|
||||
apiVersion: v1
|
||||
kind: Endpoints
|
||||
metadata:
|
||||
name: forge-external
|
||||
namespace: tailscale
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 100.98.163.89
|
||||
ports:
|
||||
- name: http
|
||||
port: 3001
|
||||
protocol: TCP
|
||||
20
argocd/manifests/tailscale-operator/ingress-forge.yaml
Normal file
20
argocd/manifests/tailscale-operator/ingress-forge.yaml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: forge-tailscale
|
||||
namespace: tailscale
|
||||
annotations:
|
||||
tailscale.com/proxy-class: "default"
|
||||
tailscale.com/proxy-group: "ingress"
|
||||
tailscale.com/tags: "tag:k8s,tag:flyio-target"
|
||||
spec:
|
||||
ingressClassName: tailscale
|
||||
defaultBackend:
|
||||
service:
|
||||
name: forge-external
|
||||
port:
|
||||
number: 3001
|
||||
tls:
|
||||
- hosts:
|
||||
- forge
|
||||
|
|
@ -7,5 +7,10 @@ namespace: tailscale
|
|||
resources:
|
||||
- ../tailscale-operator-base
|
||||
- proxygroup-ingress.yaml
|
||||
- egress-forge.yaml
|
||||
- external-secret.yaml
|
||||
- svc-forge-external.yaml
|
||||
# endpoints-forge.yaml is NOT managed by ArgoCD — Endpoints are globally
|
||||
# excluded in argocd-cm resource.exclusions (too noisy for auto-managed
|
||||
# Endpoints). Apply manually:
|
||||
# kubectl --context=minikube-indri apply -f endpoints-forge.yaml
|
||||
- ingress-forge.yaml
|
||||
|
|
|
|||
15
argocd/manifests/tailscale-operator/svc-forge-external.yaml
Normal file
15
argocd/manifests/tailscale-operator/svc-forge-external.yaml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
# ClusterIP service for Forgejo on indri. Paired with endpoints-forge.yaml
|
||||
# which provides the actual routing to indri's Tailscale IP.
|
||||
# ExternalName services don't have a ClusterIP, which the Tailscale
|
||||
# ingress operator requires.
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: forge-external
|
||||
namespace: tailscale
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 3001
|
||||
protocol: TCP
|
||||
Loading…
Add table
Add a link
Reference in a new issue