# gitea-mcp-forward-auth Kleiner Go-basierter Traefik-ForwardAuth-Microservice, der Bearer-Tokens gegen eine konfigurierbare Menge gueltiger Tokens prueft. ## Verhalten - Prueft `Authorization: Bearer `. - Validiert Token gegen SHA-256-Hashes aus: - `AUTH_PROXY_TOKEN_HASHES_DIR` (jede Datei enthaelt genau einen Token-Hash), und/oder - `AUTH_PROXY_TOKEN_HASHES` (kommagetrennte Hash-Liste). - Antwortet mit: - `200` (leer) bei gueltigem Token, - `401` bei fehlendem/ungueltigem Header oder ungueltigem Token. - `GET /healthz` ist immer ohne Auth erreichbar. - Loggt jeden Auth-Versuch strukturiert, ohne Klartext-Token. ## Sicherheitsaspekte - Token-Matching erfolgt auf Basis von SHA-256-Digests mit `crypto/subtle.ConstantTimeCompare`. - Der Service speichert nur Hashes der erlaubten Tokens, keine Klartext-Tokens in der Konfiguration. - Token werden nie im Klartext geloggt; es wird nur ein kurzer Fingerprint (`sha256:...`) geloggt. - Start bricht fail-fast ab, wenn keine gueltigen Tokens geladen werden konnten. ## Konfiguration (ENV) - `AUTH_PROXY_LISTEN_ADDR` - Default: `:8080` - Beispiel: `:8080` - `AUTH_PROXY_TOKEN_HASHES_DIR` - Optional - Pfad auf ein Verzeichnis, in dem jede Datei einen SHA-256-Token-Hash enthaelt (z. B. Kubernetes Secret Volume) - `AUTH_PROXY_TOKEN_HASHES` - Optional - Kommagetrennte Liste von SHA-256-Hashes (64 Hex-Zeichen) - Hash-Format - `abcdef...` (64 hex) oder `sha256:abcdef...` (64 hex) - `AUTH_PROXY_LOG_LEVEL` - Default: `info` - Werte wie `debug`, `info`, `warn`, `error` Hinweis: Es muss mindestens eine Hash-Quelle (`AUTH_PROXY_TOKEN_HASHES_DIR` oder `AUTH_PROXY_TOKEN_HASHES`) konfiguriert sein. ## Demo-Daten Fuer schnelle lokale Tests sind Demo-Hashes im Repo enthalten: - Verzeichnis: `demo/token-hashes/` - Datei `demo-token-1.sha256` entspricht Klartext-Token: `demo-token-1` - Datei `demo-token-2.sha256` entspricht Klartext-Token: `demo-token-2` Die Dateien enthalten nur SHA-256-Hashes und koennen gefahrlos eingecheckt werden. ## VS Code Tasks (Run + Debug + Checks) Im Projekt sind vier Tasks hinterlegt: - `Run authproxy (demo hashes)` - startet den Server mit `go run ./cmd/authproxy` - nutzt automatisch `AUTH_PROXY_TOKEN_HASHES_DIR=${workspaceFolder}/demo/token-hashes` - `Debug authproxy (delve, demo hashes)` - startet den Server im Delve-Debugger (`dlv debug ./cmd/authproxy`) - nutzt dieselben Demo-ENV-Werte - `Check authproxy 200 (demo-token-1)` - prueft per `curl`, dass ein gueltiger Demo-Token den Status `200` liefert - `Check authproxy 401 (wrong token)` - prueft per `curl`, dass ein ungueltiger Token den Status `401` liefert Starten in VS Code ueber: `Terminal -> Run Task...` Zusaetzlich gibt es eine Launch-Konfiguration fuer Breakpoints: - `.vscode/launch.json` -> `F5: Debug authproxy (demo hashes)` F5-Flow: 1. Fuer normalen Betrieb den Task `Run authproxy (demo hashes)` starten. 2. Fuer Debugging direkt die Konfiguration `F5: Debug authproxy (demo hashes)` mit `F5` starten (ohne vorherigen Run-Task). 3. Optional die Check-Tasks fuer `200` und `401` ausfuehren. ## Go Package Registry (Gitea) Dieses Repo ist auf die Gitea Go Package Registry ausgerichtet. - Registry-Muster: `https:///api/packages/{owner}/go` - In dieser Konfiguration: `https://gitea.nehmer.net/api/packages/torben/go` Beispiel lokal: ```bash go env -w GOPROXY="https://gitea.nehmer.net/api/packages/torben/go,https://proxy.golang.org,direct" ``` Annahme: Deine Angabe `https://gitea.example.com/api/packages/{owner}/go` ist ein Muster/Template. Implementiert wurde konkret `gitea.nehmer.net` mit Owner `torben`. ## Healthcheck Security `/healthz` muss nicht world-readable sein. Fuer k3s Probes und Prometheus reicht interne Erreichbarkeit im Cluster. Empfehlung: - Service als `ClusterIP` belassen (bereits in Referenzmanifesten umgesetzt) - Keine externe Ingress-Route auf `/healthz` publizieren - Zugriff auf Pod/Service-Netzwerkebene einschränken (z. B. NetworkPolicy), falls eure CNI/Policies das bereits vorsehen Annahme: In eurem Setup ist der ForwardAuth-Service nur intern erreichbar und wird nicht direkt aus dem Internet exponiert. ## Lokal bauen und starten ```bash go test ./... -v go vet ./... go build ./cmd/authproxy AUTH_PROXY_TOKEN_HASHES_DIR="./demo/token-hashes" \ AUTH_PROXY_LISTEN_ADDR=":8080" \ go run ./cmd/authproxy ``` Token-Hashes erzeugen: ```bash echo -n "my-token-1" | sha256sum | awk '{print $1}' ``` Startbeispiel mit Hashes: ```bash AUTH_PROXY_TOKEN_HASHES_DIR="./demo/token-hashes" \ AUTH_PROXY_LISTEN_ADDR=":8080" \ go run ./cmd/authproxy ``` ## Beispielaufrufe ```bash # healthcheck (ohne Auth) curl -i http://localhost:8080/healthz # fehlender Token -> 401 curl -i http://localhost:8080/ # ungueltiger Token -> 401 curl -i -H "Authorization: Bearer wrong" http://localhost:8080/ # gueltiger Token -> 200 curl -i -H "Authorization: Bearer demo-token-1" http://localhost:8080/ ``` ## Docker Das Projekt enthaelt ein Multi-Stage-Dockerfile mit statisch gelinktem Binary (`CGO_ENABLED=0`) und non-root Runtime auf Distroless. ```bash docker build -t gitea-mcp-auth-proxy:dev . docker run --rm -p 8080:8080 \ -e AUTH_PROXY_TOKEN_HASHES="," \ gitea-mcp-auth-proxy:dev ``` ## Registry-Image lokal testen Fuer einen End-to-End-Test gegen die veroeffentlichte Gitea-Container-Registry gibt es das Script `scripts/test-registry-image.sh`. Es orientiert sich am Gitea-Flow aus der Container-Registry-Doku: - Login gegen `gitea.nehmer.net` - Pull von `gitea.nehmer.net/torben/gitea-mcp-auth-proxy:` - lokaler Start des gezogenen Images mit den eingecheckten Demo-Hashes - HTTP-Pruefungen fuer `200` und `401` Default-Verhalten: - User: `torben` - Tag: `latest` - Runtime: automatisch `docker`, sonst `podman` Der Registry-Login fragt das Passwort oder einen PAT interaktiv und unsichtbar ab. Beispiel: ```bash ./scripts/test-registry-image.sh ``` Bestimmten Tag testen: ```bash ./scripts/test-registry-image.sh --tag v1.2.3 ``` Optional auf vorhandene Image-Labels pruefen: ```bash ./scripts/test-registry-image.sh \ --require-label org.opencontainers.image.source \ --require-label org.opencontainers.image.title=gitea-mcp-auth-proxy ``` Hinweis: Das Script validiert optionale Labels erst nach dem Pull. Aktuell definiert dieses Repo selbst noch keine OCI-Image-Labels im Build. ## CI/CD (Gitea Actions) - Build-Workflow: `.gitea/workflows/build.yaml` - Push auf beliebige Branches - `go vet`, `go test`, `go build` - Kein Registry-Push - Release-Workflow: `.gitea/workflows/release.yaml` - Trigger auf Tags `v*.*.*` - Buildx-Remote-Builder und Push in Registry - `latest` nur fuer stabile Tags `vX.Y.Z` - Pre-Releases (z. B. `v1.2.3-rc1`) werden nicht als `latest` markiert Wichtig: Dieses Repository baut und pusht nur Images. Das eigentliche Kubernetes-Deployment erfolgt separat ueber FluxCD Image Automation in einem anderen Repository. ## Kubernetes-Referenzmanifeste Referenzbeispiele fuer lokale Verifikation liegen unter: - `deploy/k3s/deployment.yaml` - `deploy/k3s/service.yaml` - `deploy/k3s/networkpolicy.yaml` Diese Manifeste sind bewusst minimal und nicht als produktive FluxCD-Quelle gedacht. ## Annahmen - Annahme: Go-Version ist `1.26`. - Annahme: Release-Build pusht initial nur `linux/amd64`. - Annahme: Remote BuildKit ist im Runner-Netz unter `tcp://:1234` erreichbar. - Annahme: Registry-Pfad ist `gitea.nehmer.net/torben/gitea-mcp-auth-proxy`. - Annahme: Traefik laeuft in `kube-system` mit Label `app.kubernetes.io/name=traefik`. - Annahme: Prometheus laeuft in `monitoring` mit Label `app.kubernetes.io/name=prometheus`.