mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-19 00:36:38 +00:00
Compare commits
2 Commits
coderabbit
...
cli-ws-pro
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fdf4f10d94 | ||
|
|
2b8a9f55c1 |
@@ -1,5 +1,11 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/management/internals/server"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultMgmtDataDir = "/var/lib/netbird/"
|
defaultMgmtDataDir = "/var/lib/netbird/"
|
||||||
defaultMgmtConfigDir = "/etc/netbird"
|
defaultMgmtConfigDir = "/etc/netbird"
|
||||||
@@ -16,3 +22,5 @@ const (
|
|||||||
|
|
||||||
defaultSingleAccModeDomain = "netbird.selfhosted"
|
defaultSingleAccModeDomain = "netbird.selfhosted"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var defaultWSProxyAddr = fmt.Sprintf("127.0.0.1:%d", server.ManagementLegacyPort)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
@@ -26,11 +27,11 @@ import (
|
|||||||
"github.com/netbirdio/netbird/util"
|
"github.com/netbirdio/netbird/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
var newServer = func(config *nbconfig.Config, dnsDomain, mgmtSingleAccModeDomain string, mgmtPort int, mgmtMetricsPort int, disableMetrics, disableGeoliteUpdate, userDeleteFromIDPEnabled bool) server.Server {
|
var newServer = func(config *nbconfig.Config, dnsDomain, mgmtSingleAccModeDomain string, mgmtPort int, mgmtMetricsPort int, disableMetrics, disableGeoliteUpdate, userDeleteFromIDPEnabled bool, wsProxyAddr string) server.Server {
|
||||||
return server.NewServer(config, dnsDomain, mgmtSingleAccModeDomain, mgmtPort, mgmtMetricsPort, disableMetrics, disableGeoliteUpdate, userDeleteFromIDPEnabled)
|
return server.NewServer(config, dnsDomain, mgmtSingleAccModeDomain, mgmtPort, mgmtMetricsPort, disableMetrics, disableGeoliteUpdate, userDeleteFromIDPEnabled, wsProxyAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetNewServer(fn func(config *nbconfig.Config, dnsDomain, mgmtSingleAccModeDomain string, mgmtPort int, mgmtMetricsPort int, disableMetrics, disableGeoliteUpdate, userDeleteFromIDPEnabled bool) server.Server) {
|
func SetNewServer(fn func(config *nbconfig.Config, dnsDomain, mgmtSingleAccModeDomain string, mgmtPort int, mgmtMetricsPort int, disableMetrics, disableGeoliteUpdate, userDeleteFromIDPEnabled bool, wsProxyAddr string) server.Server) {
|
||||||
newServer = fn
|
newServer = fn
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +83,10 @@ var (
|
|||||||
return fmt.Errorf("failed parsing the provided dns-domain. Valid status: %t, Length: %d", valid, len(dnsDomain))
|
return fmt.Errorf("failed parsing the provided dns-domain. Valid status: %t, Length: %d", valid, len(dnsDomain))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _, _, err := net.SplitHostPort(wsProxyAddr); err != nil {
|
||||||
|
return fmt.Errorf("invalid ws-proxy-backend-addr format: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
@@ -108,7 +113,7 @@ var (
|
|||||||
mgmtSingleAccModeDomain = ""
|
mgmtSingleAccModeDomain = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
srv := newServer(config, dnsDomain, mgmtSingleAccModeDomain, mgmtPort, mgmtMetricsPort, disableMetrics, disableGeoliteUpdate, userDeleteFromIDPEnabled)
|
srv := newServer(config, dnsDomain, mgmtSingleAccModeDomain, mgmtPort, mgmtMetricsPort, disableMetrics, disableGeoliteUpdate, userDeleteFromIDPEnabled, wsProxyAddr)
|
||||||
go func() {
|
go func() {
|
||||||
if err := srv.Start(cmd.Context()); err != nil {
|
if err := srv.Start(cmd.Context()); err != nil {
|
||||||
log.Fatalf("Server error: %v", err)
|
log.Fatalf("Server error: %v", err)
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ var (
|
|||||||
mgmtSingleAccModeDomain string
|
mgmtSingleAccModeDomain string
|
||||||
certFile string
|
certFile string
|
||||||
certKey string
|
certKey string
|
||||||
|
wsProxyAddr string
|
||||||
|
|
||||||
rootCmd = &cobra.Command{
|
rootCmd = &cobra.Command{
|
||||||
Use: "netbird-mgmt",
|
Use: "netbird-mgmt",
|
||||||
@@ -57,6 +58,7 @@ func init() {
|
|||||||
mgmtCmd.Flags().IntVar(&mgmtPort, "port", 80, "server port to listen on (defaults to 443 if TLS is enabled, 80 otherwise")
|
mgmtCmd.Flags().IntVar(&mgmtPort, "port", 80, "server port to listen on (defaults to 443 if TLS is enabled, 80 otherwise")
|
||||||
mgmtCmd.Flags().IntVar(&mgmtMetricsPort, "metrics-port", 9090, "metrics endpoint http port. Metrics are accessible under host:metrics-port/metrics")
|
mgmtCmd.Flags().IntVar(&mgmtMetricsPort, "metrics-port", 9090, "metrics endpoint http port. Metrics are accessible under host:metrics-port/metrics")
|
||||||
mgmtCmd.Flags().StringVar(&mgmtDataDir, "datadir", defaultMgmtDataDir, "server data directory location")
|
mgmtCmd.Flags().StringVar(&mgmtDataDir, "datadir", defaultMgmtDataDir, "server data directory location")
|
||||||
|
mgmtCmd.Flags().StringVar(&wsProxyAddr, "ws-proxy-backend-addr", defaultWSProxyAddr, "WebSocket proxy backend address in host:port format that the proxy will dial")
|
||||||
mgmtCmd.Flags().StringVar(&nbconfig.MgmtConfigPath, "config", defaultMgmtConfig, "Netbird config file location. Config params specified via command line (e.g. datadir) have a precedence over configuration from this file")
|
mgmtCmd.Flags().StringVar(&nbconfig.MgmtConfigPath, "config", defaultMgmtConfig, "Netbird config file location. Config params specified via command line (e.g. datadir) have a precedence over configuration from this file")
|
||||||
mgmtCmd.Flags().StringVar(&mgmtLetsencryptDomain, "letsencrypt-domain", "", "a domain to issue Let's Encrypt certificate for. Enables TLS using Let's Encrypt. Will fetch and renew certificate, and run the server with TLS")
|
mgmtCmd.Flags().StringVar(&mgmtLetsencryptDomain, "letsencrypt-domain", "", "a domain to issue Let's Encrypt certificate for. Enables TLS using Let's Encrypt. Will fetch and renew certificate, and run the server with TLS")
|
||||||
mgmtCmd.Flags().StringVar(&mgmtSingleAccModeDomain, "single-account-mode-domain", defaultSingleAccModeDomain, "Enables single account mode. This means that all the users will be under the same account grouped by the specified domain. If the installation has more than one account, the property is ineffective. Enabled by default with the default domain "+defaultSingleAccModeDomain)
|
mgmtCmd.Flags().StringVar(&mgmtSingleAccModeDomain, "single-account-mode-domain", defaultSingleAccModeDomain, "Enables single account mode. This means that all the users will be under the same account grouped by the specified domain. If the installation has more than one account, the property is ineffective. Enabled by default with the default domain "+defaultSingleAccModeDomain)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/netip"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -58,6 +57,7 @@ type BaseServer struct {
|
|||||||
mgmtSingleAccModeDomain string
|
mgmtSingleAccModeDomain string
|
||||||
mgmtMetricsPort int
|
mgmtMetricsPort int
|
||||||
mgmtPort int
|
mgmtPort int
|
||||||
|
wsProxyAddr string
|
||||||
|
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
certManager *autocert.Manager
|
certManager *autocert.Manager
|
||||||
@@ -69,7 +69,7 @@ type BaseServer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewServer initializes and configures a new Server instance
|
// NewServer initializes and configures a new Server instance
|
||||||
func NewServer(config *nbconfig.Config, dnsDomain, mgmtSingleAccModeDomain string, mgmtPort, mgmtMetricsPort int, disableMetrics, disableGeoliteUpdate, userDeleteFromIDPEnabled bool) *BaseServer {
|
func NewServer(config *nbconfig.Config, dnsDomain, mgmtSingleAccModeDomain string, mgmtPort, mgmtMetricsPort int, disableMetrics, disableGeoliteUpdate, userDeleteFromIDPEnabled bool, wsProxyAddr string) *BaseServer {
|
||||||
return &BaseServer{
|
return &BaseServer{
|
||||||
config: config,
|
config: config,
|
||||||
container: make(map[string]any),
|
container: make(map[string]any),
|
||||||
@@ -80,6 +80,7 @@ func NewServer(config *nbconfig.Config, dnsDomain, mgmtSingleAccModeDomain strin
|
|||||||
userDeleteFromIDPEnabled: userDeleteFromIDPEnabled,
|
userDeleteFromIDPEnabled: userDeleteFromIDPEnabled,
|
||||||
mgmtPort: mgmtPort,
|
mgmtPort: mgmtPort,
|
||||||
mgmtMetricsPort: mgmtMetricsPort,
|
mgmtMetricsPort: mgmtMetricsPort,
|
||||||
|
wsProxyAddr: wsProxyAddr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,6 +183,7 @@ func (s *BaseServer) Start(ctx context.Context) error {
|
|||||||
|
|
||||||
log.WithContext(ctx).Infof("management server version %s", version.NetbirdVersion())
|
log.WithContext(ctx).Infof("management server version %s", version.NetbirdVersion())
|
||||||
log.WithContext(ctx).Infof("running HTTP server and gRPC server on the same port: %s", s.listener.Addr().String())
|
log.WithContext(ctx).Infof("running HTTP server and gRPC server on the same port: %s", s.listener.Addr().String())
|
||||||
|
log.WithContext(ctx).Infof("WebSocket proxy configured to forward to: %s", s.wsProxyAddr)
|
||||||
s.serveGRPCWithHTTP(ctx, s.listener, rootHandler, tlsEnabled)
|
s.serveGRPCWithHTTP(ctx, s.listener, rootHandler, tlsEnabled)
|
||||||
|
|
||||||
s.update = version.NewUpdate("nb/management")
|
s.update = version.NewUpdate("nb/management")
|
||||||
@@ -252,7 +254,7 @@ func updateMgmtConfig(ctx context.Context, path string, config *nbconfig.Config)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *BaseServer) handlerFunc(gRPCHandler *grpc.Server, httpHandler http.Handler, meter metric.Meter) http.Handler {
|
func (s *BaseServer) handlerFunc(gRPCHandler *grpc.Server, httpHandler http.Handler, meter metric.Meter) http.Handler {
|
||||||
wsProxy := wsproxyserver.New(netip.AddrPortFrom(netip.AddrFrom4([4]byte{127, 0, 0, 1}), ManagementLegacyPort), wsproxyserver.WithOTelMeter(meter))
|
wsProxy := wsproxyserver.New(s.wsProxyAddr, wsproxyserver.WithOTelMeter(meter))
|
||||||
|
|
||||||
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||||
switch {
|
switch {
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
// nolint:gosec
|
// nolint:gosec
|
||||||
_ "net/http/pprof"
|
_ "net/http/pprof"
|
||||||
"net/netip"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||||
@@ -46,6 +45,7 @@ var (
|
|||||||
defaultSignalSSLDir string
|
defaultSignalSSLDir string
|
||||||
signalCertFile string
|
signalCertFile string
|
||||||
signalCertKey string
|
signalCertKey string
|
||||||
|
wsProxyBackendAddr string
|
||||||
|
|
||||||
signalKaep = grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
|
signalKaep = grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
|
||||||
MinTime: 5 * time.Second,
|
MinTime: 5 * time.Second,
|
||||||
@@ -63,10 +63,10 @@ var (
|
|||||||
Use: "run",
|
Use: "run",
|
||||||
Short: "start NetBird Signal Server daemon",
|
Short: "start NetBird Signal Server daemon",
|
||||||
SilenceUsage: true,
|
SilenceUsage: true,
|
||||||
PreRun: func(cmd *cobra.Command, args []string) {
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
err := util.InitLog(logLevel, logFile)
|
err := util.InitLog(logLevel, logFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed initializing log %v", err)
|
return fmt.Errorf("failed initializing log: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
@@ -79,6 +79,10 @@ var (
|
|||||||
tlsEnabled = true
|
tlsEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _, _, err := net.SplitHostPort(wsProxyBackendAddr); err != nil {
|
||||||
|
return fmt.Errorf("invalid ws-proxy-backend-addr format: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
if !userPort {
|
if !userPort {
|
||||||
// different defaults for signalPort
|
// different defaults for signalPort
|
||||||
if tlsEnabled {
|
if tlsEnabled {
|
||||||
@@ -87,6 +91,8 @@ var (
|
|||||||
signalPort = 80
|
signalPort = 80
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
@@ -160,6 +166,7 @@ var (
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("signal server version %s", version.NetbirdVersion())
|
log.Infof("signal server version %s", version.NetbirdVersion())
|
||||||
|
log.Infof("WebSocket proxy configured to forward to: %s", wsProxyBackendAddr)
|
||||||
log.Infof("started Signal Service")
|
log.Infof("started Signal Service")
|
||||||
|
|
||||||
SetupCloseHandler()
|
SetupCloseHandler()
|
||||||
@@ -254,7 +261,7 @@ func startServerWithCertManager(certManager *autocert.Manager, grpcRootHandler h
|
|||||||
}
|
}
|
||||||
|
|
||||||
func grpcHandlerFunc(grpcServer *grpc.Server, meter metric.Meter) http.Handler {
|
func grpcHandlerFunc(grpcServer *grpc.Server, meter metric.Meter) http.Handler {
|
||||||
wsProxy := wsproxyserver.New(netip.AddrPortFrom(netip.AddrFrom4([4]byte{127, 0, 0, 1}), legacyGRPCPort), wsproxyserver.WithOTelMeter(meter))
|
wsProxy := wsproxyserver.New(wsProxyBackendAddr, wsproxyserver.WithOTelMeter(meter))
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
switch {
|
switch {
|
||||||
@@ -328,5 +335,6 @@ func init() {
|
|||||||
runCmd.Flags().StringVar(&signalLetsencryptDomain, "letsencrypt-domain", "", "a domain to issue Let's Encrypt certificate for. Enables TLS using Let's Encrypt. Will fetch and renew certificate, and run the server with TLS")
|
runCmd.Flags().StringVar(&signalLetsencryptDomain, "letsencrypt-domain", "", "a domain to issue Let's Encrypt certificate for. Enables TLS using Let's Encrypt. Will fetch and renew certificate, and run the server with TLS")
|
||||||
runCmd.Flags().StringVar(&signalCertFile, "cert-file", "", "Location of your SSL certificate. Can be used when you have an existing certificate and don't want a new certificate be generated automatically. If letsencrypt-domain is specified this property has no effect")
|
runCmd.Flags().StringVar(&signalCertFile, "cert-file", "", "Location of your SSL certificate. Can be used when you have an existing certificate and don't want a new certificate be generated automatically. If letsencrypt-domain is specified this property has no effect")
|
||||||
runCmd.Flags().StringVar(&signalCertKey, "cert-key", "", "Location of your SSL certificate private key. Can be used when you have an existing certificate and don't want a new certificate be generated automatically. If letsencrypt-domain is specified this property has no effect")
|
runCmd.Flags().StringVar(&signalCertKey, "cert-key", "", "Location of your SSL certificate private key. Can be used when you have an existing certificate and don't want a new certificate be generated automatically. If letsencrypt-domain is specified this property has no effect")
|
||||||
|
runCmd.Flags().StringVar(&wsProxyBackendAddr, "ws-proxy-backend-addr", fmt.Sprintf("127.0.0.1:%d", legacyGRPCPort), "WebSocket proxy backend address in host:port format that the proxy will dial")
|
||||||
setFlagsFromEnvVars(runCmd)
|
setFlagsFromEnvVars(runCmd)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/netip"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -23,7 +22,7 @@ const (
|
|||||||
|
|
||||||
// Config contains the configuration for the WebSocket proxy.
|
// Config contains the configuration for the WebSocket proxy.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
LocalGRPCAddr netip.AddrPort
|
LocalGRPCAddr string
|
||||||
Path string
|
Path string
|
||||||
MetricsRecorder MetricsRecorder
|
MetricsRecorder MetricsRecorder
|
||||||
}
|
}
|
||||||
@@ -35,7 +34,7 @@ type Proxy struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new WebSocket proxy instance with optional configuration
|
// New creates a new WebSocket proxy instance with optional configuration
|
||||||
func New(localGRPCAddr netip.AddrPort, opts ...Option) *Proxy {
|
func New(localGRPCAddr string, opts ...Option) *Proxy {
|
||||||
config := Config{
|
config := Config{
|
||||||
LocalGRPCAddr: localGRPCAddr,
|
LocalGRPCAddr: localGRPCAddr,
|
||||||
Path: wsproxy.ProxyPath,
|
Path: wsproxy.ProxyPath,
|
||||||
@@ -81,7 +80,7 @@ func (p *Proxy) handleWebSocket(w http.ResponseWriter, r *http.Request) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
log.Debugf("WebSocket proxy attempting to connect to local gRPC at %s", p.config.LocalGRPCAddr)
|
log.Debugf("WebSocket proxy attempting to connect to local gRPC at %s", p.config.LocalGRPCAddr)
|
||||||
tcpConn, err := net.DialTimeout("tcp", p.config.LocalGRPCAddr.String(), dialTimeout)
|
tcpConn, err := net.DialTimeout("tcp", p.config.LocalGRPCAddr, dialTimeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.metrics.RecordError(ctx, "tcp_dial_failed")
|
p.metrics.RecordError(ctx, "tcp_dial_failed")
|
||||||
log.Warnf("Failed to connect to local gRPC server at %s: %v", p.config.LocalGRPCAddr, err)
|
log.Warnf("Failed to connect to local gRPC server at %s: %v", p.config.LocalGRPCAddr, err)
|
||||||
|
|||||||
Reference in New Issue
Block a user