control-api: every route now carries a mandatory access level (admin / agent / open) in a route table. All /api/v1/admin/* require the admin token; the write calls of validator-agent and prober (self-check, events, results, complete) require a separate static agent token; register, heartbeat and fetching the assignment stay open. Tokens come from env vars, are compared in constant time and never logged. An empty token leaves that level open with a startup warning (backward compatible). validator-agent / prober: apiclient sends the agent token only to control-api. admin-dashboard: login/password (from env) with a stateless HMAC session cookie, Origin-based CSRF check, per-IP brute-force throttle, HX-Redirect for htmx polls, logout in the sidebar; the dashboard calls control-api with the admin token. Login page layout fixed after review. Also: env plumbing in docker-compose/rxprod-compose/systemd/config examples, e2e script with token assertions, tests, docs (API, SETUP, USAGE, DASHBOARD, README), plan and review under docs/changes/, bin/ rebuilt with new SHA256SUMS. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
44 lines
1.2 KiB
Go
44 lines
1.2 KiB
Go
// Command prober runs on one of the external test sites. It polls the
|
|
// Control API for the set of floating IPs currently under test and probes
|
|
// each directly (TCP connect + ICMP echo) to measure inbound reachability
|
|
// from this vantage point.
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"flag"
|
|
"log/slog"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
|
|
"cloudipvalidator/internal/config"
|
|
"cloudipvalidator/internal/probercore"
|
|
)
|
|
|
|
func main() {
|
|
configPath := flag.String("config", "configs/prober.yaml", "path to prober config file")
|
|
flag.Parse()
|
|
|
|
log := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
|
|
|
|
cfg, err := config.LoadProber(*configPath)
|
|
if err != nil {
|
|
log.Error("load config", "err", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
|
defer stop()
|
|
|
|
token := os.Getenv(cfg.ControlAPITokenEnv)
|
|
if token == "" {
|
|
log.Warn("agent token is not set: result calls will be rejected by an authenticated control-api", "env", cfg.ControlAPITokenEnv)
|
|
}
|
|
prober := probercore.New(cfg, log).WithToken(token)
|
|
if err := prober.Run(ctx); err != nil && err != context.Canceled {
|
|
log.Error("prober stopped", "err", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|