feat: tunnel JWT auth
Tunnel method now requires Bearer JWT (HMAC-HS256) in gRPC metadata.
- internal/auth: pure-stdlib verifier + issuer + revoked-jti list
- internal/tunnel: per-target rate limiter + egress allowlist with
wildcard support + crypto/rand frame padding to {1KB, 4KB, 16KB}
- cmd/server reads /etc/stats-gateway/{jwt.key,tunnel.yaml,revoked.txt}
via --config-dir flag
- cmd/issue-token Go binary wraps auth.Issue
- configs/tunnel.yaml example with projectshitpost wildcard
Tests: 13 PASS across 5 packages.
This commit is contained in:
+35
-2
@@ -1,20 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
statsv1 "github.com/bergabruh/stats-gateway/gen/stats/v1"
|
||||
"github.com/bergabruh/stats-gateway/internal/auth"
|
||||
"github.com/bergabruh/stats-gateway/internal/service"
|
||||
"github.com/bergabruh/stats-gateway/internal/storage"
|
||||
"github.com/bergabruh/stats-gateway/internal/tunnel"
|
||||
)
|
||||
|
||||
func main() {
|
||||
addr := flag.String("addr", "127.0.0.1:50051", "listen address")
|
||||
dbPath := flag.String("db", "/var/lib/stats-gateway/stats.db", "sqlite path")
|
||||
cfgDir := flag.String("config-dir", "/etc/stats-gateway", "config dir (jwt.key, tunnel.yaml, revoked.txt)")
|
||||
flag.Parse()
|
||||
|
||||
st, err := storage.Open(*dbPath)
|
||||
@@ -23,15 +30,41 @@ func main() {
|
||||
}
|
||||
defer st.Close()
|
||||
|
||||
secret, err := os.ReadFile(filepath.Join(*cfgDir, "jwt.key"))
|
||||
if err != nil {
|
||||
log.Fatalf("read jwt.key: %v", err)
|
||||
}
|
||||
secret = bytes.TrimSpace(secret)
|
||||
|
||||
cfgBytes, err := os.ReadFile(filepath.Join(*cfgDir, "tunnel.yaml"))
|
||||
if err != nil {
|
||||
log.Fatalf("read tunnel.yaml: %v", err)
|
||||
}
|
||||
var tunnelCfg struct {
|
||||
Egress tunnel.EgressConfig `yaml:"egress"`
|
||||
}
|
||||
if err := yaml.Unmarshal(cfgBytes, &tunnelCfg); err != nil {
|
||||
log.Fatalf("parse tunnel.yaml: %v", err)
|
||||
}
|
||||
|
||||
revoked, err := auth.LoadRevokedFile(filepath.Join(*cfgDir, "revoked.txt"))
|
||||
if err != nil {
|
||||
log.Fatalf("load revoked: %v", err)
|
||||
}
|
||||
|
||||
verifier := auth.NewVerifier(secret, revoked)
|
||||
handler := tunnel.NewHandler(tunnelCfg.Egress)
|
||||
|
||||
lis, err := net.Listen("tcp", *addr)
|
||||
if err != nil {
|
||||
log.Fatalf("listen: %v", err)
|
||||
}
|
||||
|
||||
srv := grpc.NewServer()
|
||||
statsv1.RegisterSpeedStatusServer(srv, service.New(st))
|
||||
statsv1.RegisterSpeedStatusServer(srv, service.New(st, verifier, handler))
|
||||
|
||||
log.Printf("stats-gateway listening on %s", *addr)
|
||||
log.Printf("stats-gateway listening on %s (egress=%d targets, rate=%.0fmbps)",
|
||||
*addr, len(tunnelCfg.Egress.Allowed), tunnelCfg.Egress.RateMbps)
|
||||
if err := srv.Serve(lis); err != nil {
|
||||
log.Fatalf("serve: %v", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user