// tera-accessd owns the target's dynamically configured management listeners. package main import ( "context" "errors" "log" "net" "os" "os/signal" "path/filepath" "strings" "syscall" "tera-clone/services/tera-api/internal/managementaccess" "tera-clone/services/tera-api/internal/webgateway" ) func main() { socketPath := accessGetenv("TERA_ACCESSD_SOCKET", managementaccess.DefaultSocketPath) handler, err := webgateway.NewHandler(webgateway.Options{ WebUpstream: os.Getenv("TERA_ACCESSD_WEB_UPSTREAM"), StaticRoot: accessGetenv("TERA_ACCESSD_STATIC_ROOT", "/usr/share/tera-web"), APIUpstream: accessGetenv("TERA_ACCESSD_API_UPSTREAM", "http://127.0.0.1:8082"), SessionUpstream: accessGetenv("TERA_ACCESSD_SESSION_UPSTREAM", "http://127.0.0.1:8081"), }) if err != nil { log.Fatalf("tera-accessd web setup failed: %v", err) } runtime, err := managementaccess.NewRuntime(managementaccess.RuntimeOptions{ BindHost: accessGetenv("TERA_ACCESSD_BIND_HOST", "0.0.0.0"), Handler: handler, CertFile: accessGetenv("TERA_ACCESSD_TLS_CERT", "/var/lib/tera-accessd/tls/server.crt"), KeyFile: accessGetenv("TERA_ACCESSD_TLS_KEY", "/var/lib/tera-accessd/tls/server.key"), TLSHosts: accessGetenvList("TERA_ACCESSD_TLS_HOSTS", []string{"192.168.0.223", "localhost", "127.0.0.1"}), }) if err != nil { log.Fatalf("tera-accessd runtime setup failed: %v", err) } defer runtime.Close() listener, err := listenControlSocket(socketPath) if err != nil { log.Fatalf("tera-accessd control socket setup failed: %v", err) } defer func() { _ = listener.Close() _ = os.Remove(socketPath) }() server := managementaccess.SocketServer{Controller: runtime} errorsChannel := make(chan error, 1) go func() { errorsChannel <- server.Serve(listener) }() log.Printf("tera-accessd serving management access control on %s", socketPath) signalContext, stopSignals := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stopSignals() select { case <-signalContext.Done(): _ = listener.Close() if err := <-errorsChannel; err != nil { log.Printf("tera-accessd control shutdown failed: %v", err) } case err := <-errorsChannel: if err != nil { log.Fatalf("tera-accessd control service failed: %v", err) } } } func listenControlSocket(socketPath string) (net.Listener, error) { if socketPath == "" || !filepath.IsAbs(socketPath) { return nil, errors.New("TERA_ACCESSD_SOCKET must be an absolute path") } if err := os.MkdirAll(filepath.Dir(socketPath), 0o750); err != nil { return nil, err } if info, err := os.Lstat(socketPath); err == nil { if info.Mode()&os.ModeSocket == 0 { return nil, errors.New("refusing to replace non-socket management access path") } if err := os.Remove(socketPath); err != nil { return nil, err } } else if !os.IsNotExist(err) { return nil, err } listener, err := net.Listen("unix", socketPath) if err != nil { return nil, err } if err := os.Chmod(socketPath, 0o660); err != nil { _ = listener.Close() return nil, err } return listener, nil } func accessGetenv(key, fallback string) string { if value := strings.TrimSpace(os.Getenv(key)); value != "" { return value } return fallback } func accessGetenvList(key string, fallback []string) []string { value := strings.TrimSpace(os.Getenv(key)) if value == "" { return fallback } result := make([]string, 0) for _, item := range strings.Split(value, ",") { if item = strings.TrimSpace(item); item != "" { result = append(result, item) } } return result }