hub: S1 wgsync (pinned-SSH push + declarative reconciler) + /admin/wg API + env wiring
internal/wgsync: x/crypto/ssh client with ssh.FixedHostKey pin (no insecure fallback), forced-command exec, ok/applied response contract; Reconciler pushes the FULL peer list on Trigger or 5-min tick (drift repair by construction). internal/api/wg.go: PUT/GET /admin/wg/endpoint + POST/DELETE/GET /admin/wg/peers, global-key-only, pubkey in body (base64 vs URL), sync ok|deferred|disabled. main.go: WG_ENDPOINT_SSH_* env wiring, disabled-with-INFO when unconfigured. Groups B/C/D tests incl. in-process SSH server; red-proofs b/c/d run + reverted. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -20,6 +20,7 @@ import (
|
||||
"gitea.dooplex.hu/admin/felhom-hub/internal/notify"
|
||||
"gitea.dooplex.hu/admin/felhom-hub/internal/store"
|
||||
"gitea.dooplex.hu/admin/felhom-hub/internal/web"
|
||||
"gitea.dooplex.hu/admin/felhom-hub/internal/wgsync"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
@@ -316,6 +317,37 @@ func main() {
|
||||
apiHandler.SetLatestVersionProvider(versionChecker)
|
||||
}
|
||||
|
||||
// S1 offsite connectivity: the WG peer-sync reconciler (internal/wgsync). Config from env
|
||||
// (mirror of the Resend/registry pattern): the SSH private key from the mounted Secret file,
|
||||
// the (non-secret) pinned host key from plain env. Any piece missing → disabled with an INFO
|
||||
// log; the /admin/wg mutations still work against the DB and report sync:"disabled".
|
||||
{
|
||||
wgAddr := os.Getenv("WG_ENDPOINT_SSH_ADDR")
|
||||
wgUser := os.Getenv("WG_ENDPOINT_SSH_USER")
|
||||
if wgUser == "" {
|
||||
wgUser = "felhom-peersync"
|
||||
}
|
||||
wgKeyFile := os.Getenv("WG_ENDPOINT_SSH_KEY_FILE")
|
||||
wgHostKey := os.Getenv("WG_ENDPOINT_SSH_HOSTKEY")
|
||||
if wgAddr != "" && wgKeyFile != "" && wgHostKey != "" {
|
||||
keyPEM, err := os.ReadFile(wgKeyFile)
|
||||
if err != nil {
|
||||
logger.Printf("[ERROR] WG peer-sync disabled: read key file %s: %v", wgKeyFile, err)
|
||||
} else if wgClient, err := wgsync.New(wgsync.Config{
|
||||
Addr: wgAddr, User: wgUser, PrivateKey: keyPEM, HostKeyLine: wgHostKey,
|
||||
}, logger); err != nil {
|
||||
logger.Printf("[ERROR] WG peer-sync disabled: %v", err)
|
||||
} else {
|
||||
wgReconciler := wgsync.NewReconciler(dataStore, wgClient, logger)
|
||||
go wgReconciler.Run(ctx)
|
||||
apiHandler.SetWGSyncer(wgReconciler)
|
||||
logger.Printf("[INFO] WG peer-sync enabled (endpoint %s, user %s)", wgAddr, wgUser)
|
||||
}
|
||||
} else {
|
||||
logger.Printf("[INFO] WG peer-sync disabled (endpoint not configured)")
|
||||
}
|
||||
}
|
||||
|
||||
// Session cleanup — removes expired sessions every hour
|
||||
go webServer.CleanupSessions(ctx)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user