b8d18e819c
Build and Test / verify (push) Successful in 32s
Build and Push Container Image / build-and-push-image (push) Successful in 52s
239 lines
7.8 KiB
Markdown
239 lines
7.8 KiB
Markdown
# gitea-mcp-forward-auth
|
|
|
|
Kleiner Go-basierter Traefik-ForwardAuth-Microservice, der Bearer-Tokens gegen eine konfigurierbare Menge gueltiger Tokens prueft.
|
|
|
|
## Verhalten
|
|
|
|
- Prueft `Authorization: Bearer <token>`.
|
|
- 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://<gitea-host>/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="<sha256-hash-1>,<sha256-hash-2>" \
|
|
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:<tag>`
|
|
- 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.
|
|
|
|
Auth-Handling ist absichtlich ephemeral:
|
|
|
|
- Das Script schreibt keine Credentials in `~/.docker/config.json`.
|
|
- Fuer `docker` wird ein temporäres `DOCKER_CONFIG`-Verzeichnis verwendet.
|
|
- Fuer `podman` wird eine temporäre `REGISTRY_AUTH_FILE` verwendet.
|
|
- Beides wird beim Script-Ende automatisch geloescht.
|
|
|
|
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://<default-gateway>: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`. |