feat: add S3/SigV4 proxy handler for MinIO JWT auth
- New s3/sigv4.go: JWT → SigV4 converter proxy * Validates JWT via JWKS * Checks s3:read/s3:write permissions * Forwards requests to MinIO with SigV4 signature - Router: Add /v1/s3/* routing to S3Handler - Gateway main: Initialize S3Handler with MinIO credentials - Proxy: Add JWTValidator() getter for s3 handler - Env vars: MINIO_ENDPOINT, MINIO_ACCESS_KEY, MINIO_SECRET_KEY
This commit is contained in:
@@ -2,17 +2,19 @@ package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"forgejo.riotpiao.com/rock/homelab-frontend/internal/serviceadapter"
|
||||
)
|
||||
|
||||
// Router implements an HTTP handler that routes health endpoints,
|
||||
// ServiceAdapter X-Service requests, Temporal workflow endpoints,
|
||||
// and other requests to upstream handlers.
|
||||
// S3/SigV4 endpoints, and other requests to upstream handlers.
|
||||
type Router struct {
|
||||
healthChecker *HealthChecker
|
||||
dispatcher *serviceadapter.Dispatcher
|
||||
temporalHandler http.Handler
|
||||
s3Handler http.Handler // S3/SigV4 proxy
|
||||
upstreamHandler http.Handler
|
||||
}
|
||||
|
||||
@@ -20,12 +22,14 @@ type Router struct {
|
||||
// Health endpoints (/healthz and /readyz) are handled locally.
|
||||
// X-Service requests are dispatched via ServiceAdapter CRD.
|
||||
// Temporal endpoints (/workflow*) are routed to temporalHandler.
|
||||
// S3 endpoints (/v1/s3/*) are routed to s3Handler.
|
||||
// All other paths are passed to the upstream handler.
|
||||
func NewRouter(healthChecker *HealthChecker, dispatcher *serviceadapter.Dispatcher, temporalHandler http.Handler, upstreamHandler http.Handler) *Router {
|
||||
func NewRouter(healthChecker *HealthChecker, dispatcher *serviceadapter.Dispatcher, temporalHandler http.Handler, s3Handler http.Handler, upstreamHandler http.Handler) *Router {
|
||||
return &Router{
|
||||
healthChecker: healthChecker,
|
||||
dispatcher: dispatcher,
|
||||
temporalHandler: temporalHandler,
|
||||
s3Handler: s3Handler,
|
||||
upstreamHandler: upstreamHandler,
|
||||
}
|
||||
}
|
||||
@@ -35,7 +39,8 @@ func NewRouter(healthChecker *HealthChecker, dispatcher *serviceadapter.Dispatch
|
||||
// 1. /healthz and /readyz to health handlers
|
||||
// 2. X-Service header to ServiceAdapter dispatcher (phase 8)
|
||||
// 3. /workflow* to temporal handler
|
||||
// 4. All other paths to upstream handler (phase 0-7)
|
||||
// 4. /v1/s3/* to S3/SigV4 handler
|
||||
// 5. All other paths to upstream handler (phase 0-7)
|
||||
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
// Health endpoints first
|
||||
switch req.URL.Path {
|
||||
@@ -62,6 +67,18 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// S3/SigV4 proxy endpoints
|
||||
if req.URL.Path != "" && req.URL.Path[0] == '/' && len(req.URL.Path) > 1 {
|
||||
// Check for /v1/s3/* pattern
|
||||
parts := strings.Split(strings.TrimPrefix(req.URL.Path, "/"), "/")
|
||||
if len(parts) >= 3 && parts[0] == "v1" && parts[1] == "s3" {
|
||||
if r.s3Handler != nil {
|
||||
r.s3Handler.ServeHTTP(w, req)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default: upstream handler (all other paths)
|
||||
r.upstreamHandler.ServeHTTP(w, req)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user