mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-18 16:26:38 +00:00
use embedded netbird agent for tunneling
This commit is contained in:
@@ -52,7 +52,7 @@ func run(cmd *cobra.Command, args []string) error {
|
|||||||
log.Infof("Starting Netbird Proxy - %s", version.Short())
|
log.Infof("Starting Netbird Proxy - %s", version.Short())
|
||||||
log.Debugf("Full version info: %s", version.String())
|
log.Debugf("Full version info: %s", version.String())
|
||||||
log.Info("Configuration loaded successfully")
|
log.Info("Configuration loaded successfully")
|
||||||
log.Infof("Listen Address: %s", config.ListenAddress)
|
log.Infof("Listen Address: %s", config.ReverseProxy.ListenAddress)
|
||||||
log.Infof("Log Level: %s", config.LogLevel)
|
log.Infof("Log Level: %s", config.LogLevel)
|
||||||
|
|
||||||
// Create server instance
|
// Create server instance
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"listen_address": ":443",
|
|
||||||
"read_timeout": "30s",
|
"read_timeout": "30s",
|
||||||
"write_timeout": "30s",
|
"write_timeout": "30s",
|
||||||
"idle_timeout": "60s",
|
"idle_timeout": "60s",
|
||||||
@@ -8,20 +7,24 @@
|
|||||||
"grpc_listen_address": ":50051",
|
"grpc_listen_address": ":50051",
|
||||||
"proxy_id": "proxy-1",
|
"proxy_id": "proxy-1",
|
||||||
"enable_grpc": true,
|
"enable_grpc": true,
|
||||||
"http_listen_address": ":80",
|
"reverse_proxy": {
|
||||||
"enable_https": false,
|
"listen_address": ":443",
|
||||||
"tls_email": "your-email@example.com",
|
"management_url": "https://api.netbird.io",
|
||||||
"cert_cache_dir": "./certs",
|
"http_listen_address": ":80",
|
||||||
"oidc_config": {
|
"enable_https": false,
|
||||||
"provider_url": "https://your-oidc-provider.com",
|
"tls_email": "your-email@example.com",
|
||||||
"client_id": "your-client-id",
|
"cert_cache_dir": "./certs",
|
||||||
"client_secret": "your-client-secret-if-needed",
|
"oidc_config": {
|
||||||
"redirect_url": "http://localhost:80/auth/callback",
|
"provider_url": "https://your-oidc-provider.com",
|
||||||
"scopes": ["openid", "profile", "email"],
|
"client_id": "your-client-id",
|
||||||
"jwt_keys_location": "https://your-oidc-provider.com/.well-known/jwks.json",
|
"client_secret": "your-client-secret-if-needed",
|
||||||
"jwt_issuer": "https://your-oidc-provider.com/",
|
"redirect_url": "http://localhost:80/auth/callback",
|
||||||
"jwt_audience": ["your-api-identifier-or-client-id"],
|
"scopes": ["openid", "profile", "email"],
|
||||||
"jwt_idp_signkey_refresh_enabled": false,
|
"jwt_keys_location": "https://your-oidc-provider.com/.well-known/jwks.json",
|
||||||
"session_cookie_name": "auth_session"
|
"jwt_issuer": "https://your-oidc-provider.com/",
|
||||||
|
"jwt_audience": ["your-api-identifier-or-client-id"],
|
||||||
|
"jwt_idp_signkey_refresh_enabled": false,
|
||||||
|
"session_cookie_name": "auth_session"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package reverseproxy
|
package reverseproxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/client/embed"
|
||||||
"github.com/netbirdio/netbird/proxy/internal/auth"
|
"github.com/netbirdio/netbird/proxy/internal/auth"
|
||||||
"github.com/netbirdio/netbird/proxy/internal/auth/oidc"
|
"github.com/netbirdio/netbird/proxy/internal/auth/oidc"
|
||||||
)
|
)
|
||||||
@@ -12,28 +12,28 @@ import (
|
|||||||
// Config holds the reverse proxy configuration
|
// Config holds the reverse proxy configuration
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// ListenAddress is the address to listen on for HTTPS (default ":443")
|
// ListenAddress is the address to listen on for HTTPS (default ":443")
|
||||||
ListenAddress string
|
ListenAddress string `env:"NB_REVERSE_PROXY_LISTEN_ADDRESS" envDefault:":443" json:"listen_address"`
|
||||||
|
|
||||||
|
// ManagementURL is the URL of the management server
|
||||||
|
ManagementURL string `env:"NB_REVERSE_PROXY_MANAGEMENT_URL" json:"management_url"`
|
||||||
|
|
||||||
// HTTPListenAddress is the address for HTTP (default ":80")
|
// HTTPListenAddress is the address for HTTP (default ":80")
|
||||||
// Used for ACME challenges when HTTPS is enabled, or as main listener when HTTPS is disabled
|
// Used for ACME challenges when HTTPS is enabled, or as main listener when HTTPS is disabled
|
||||||
HTTPListenAddress string
|
HTTPListenAddress string `env:"NB_REVERSE_PROXY_HTTP_LISTEN_ADDRESS" envDefault:":80" json:"http_listen_address"`
|
||||||
|
|
||||||
// EnableHTTPS enables automatic HTTPS with Let's Encrypt
|
// EnableHTTPS enables automatic HTTPS with Let's Encrypt
|
||||||
EnableHTTPS bool
|
EnableHTTPS bool `env:"NB_REVERSE_PROXY_ENABLE_HTTPS" envDefault:"false" json:"enable_https"`
|
||||||
|
|
||||||
// TLSEmail is the email for Let's Encrypt registration
|
// TLSEmail is the email for Let's Encrypt registration
|
||||||
TLSEmail string
|
TLSEmail string `env:"NB_REVERSE_PROXY_TLS_EMAIL" json:"tls_email"`
|
||||||
|
|
||||||
// CertCacheDir is the directory to cache certificates (default "./certs")
|
// CertCacheDir is the directory to cache certificates (default "./certs")
|
||||||
CertCacheDir string
|
CertCacheDir string `env:"NB_REVERSE_PROXY_CERT_CACHE_DIR" envDefault:"./certs" json:"cert_cache_dir"`
|
||||||
|
|
||||||
// RequestDataCallback is called for each proxied request with metrics
|
|
||||||
RequestDataCallback RequestDataCallback
|
|
||||||
|
|
||||||
// OIDCConfig is the global OIDC/OAuth configuration for authentication
|
// OIDCConfig is the global OIDC/OAuth configuration for authentication
|
||||||
// This is shared across all routes that use Bearer authentication
|
// This is shared across all routes that use Bearer authentication
|
||||||
// If nil, routes with Bearer auth will fail to initialize
|
// If nil, routes with Bearer auth will fail to initialize
|
||||||
OIDCConfig *oidc.Config
|
OIDCConfig *oidc.Config `json:"oidc_config"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RouteConfig defines a routing configuration
|
// RouteConfig defines a routing configuration
|
||||||
@@ -50,10 +50,8 @@ type RouteConfig struct {
|
|||||||
// Must have at least one entry. Use "/" or "" for the default/catch-all route.
|
// Must have at least one entry. Use "/" or "" for the default/catch-all route.
|
||||||
PathMappings map[string]string
|
PathMappings map[string]string
|
||||||
|
|
||||||
// Conn is the network connection to use for this route
|
SetupKey string
|
||||||
// This allows routing through specific tunnels (e.g., WireGuard) per route
|
nbClient *embed.Client
|
||||||
// This connection will be reused for all requests to this route
|
|
||||||
Conn net.Conn
|
|
||||||
|
|
||||||
// AuthConfig is optional authentication configuration for this route
|
// AuthConfig is optional authentication configuration for this route
|
||||||
// Configure ONE of: BasicAuth, PIN, or Bearer (JWT/OIDC)
|
// Configure ONE of: BasicAuth, PIN, or Bearer (JWT/OIDC)
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
package reverseproxy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// defaultConn is a lazy connection wrapper that uses the standard network dialer
|
|
||||||
// This is useful for testing or development when not using WireGuard tunnels
|
|
||||||
type defaultConn struct {
|
|
||||||
dialer *net.Dialer
|
|
||||||
mu sync.Mutex
|
|
||||||
conns map[string]net.Conn // cache connections by "network:address"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dc *defaultConn) Read(b []byte) (n int, err error) {
|
|
||||||
return 0, fmt.Errorf("Read not supported on defaultConn - use dial via Transport")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dc *defaultConn) Write(b []byte) (n int, err error) {
|
|
||||||
return 0, fmt.Errorf("Write not supported on defaultConn - use dial via Transport")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dc *defaultConn) Close() error {
|
|
||||||
dc.mu.Lock()
|
|
||||||
defer dc.mu.Unlock()
|
|
||||||
|
|
||||||
for _, conn := range dc.conns {
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
dc.conns = make(map[string]net.Conn)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dc *defaultConn) LocalAddr() net.Addr { return nil }
|
|
||||||
func (dc *defaultConn) RemoteAddr() net.Addr { return nil }
|
|
||||||
func (dc *defaultConn) SetDeadline(t time.Time) error { return nil }
|
|
||||||
func (dc *defaultConn) SetReadDeadline(t time.Time) error { return nil }
|
|
||||||
func (dc *defaultConn) SetWriteDeadline(t time.Time) error { return nil }
|
|
||||||
|
|
||||||
// NewDefaultConn creates a connection wrapper that uses the standard network dialer
|
|
||||||
// This is useful for testing or development when not using WireGuard tunnels
|
|
||||||
// The actual dialing happens when the HTTP Transport calls DialContext
|
|
||||||
func NewDefaultConn() net.Conn {
|
|
||||||
return &defaultConn{
|
|
||||||
dialer: &net.Dialer{
|
|
||||||
Timeout: 30 * time.Second,
|
|
||||||
KeepAlive: 30 * time.Second,
|
|
||||||
},
|
|
||||||
conns: make(map[string]net.Conn),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
package reverseproxy
|
package reverseproxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -187,32 +185,15 @@ func (p *Proxy) createProxy(routeConfig *RouteConfig, target string) *httputil.R
|
|||||||
// Create reverse proxy
|
// Create reverse proxy
|
||||||
proxy := httputil.NewSingleHostReverseProxy(targetURL)
|
proxy := httputil.NewSingleHostReverseProxy(targetURL)
|
||||||
|
|
||||||
// Check if this is a defaultConn (for testing)
|
// Configure transport to use the provided connection (WireGuard, etc.)
|
||||||
if dc, ok := routeConfig.Conn.(*defaultConn); ok {
|
proxy.Transport = &http.Transport{
|
||||||
// For defaultConn, use its dialer directly
|
DialContext: routeConfig.nbClient.DialContext,
|
||||||
proxy.Transport = &http.Transport{
|
MaxIdleConns: 1,
|
||||||
DialContext: dc.dialer.DialContext,
|
MaxIdleConnsPerHost: 1,
|
||||||
MaxIdleConns: 100,
|
IdleConnTimeout: 0, // Keep alive indefinitely
|
||||||
IdleConnTimeout: 90 * time.Second,
|
DisableKeepAlives: false,
|
||||||
TLSHandshakeTimeout: 10 * time.Second,
|
TLSHandshakeTimeout: 10 * time.Second,
|
||||||
ExpectContinueTimeout: 1 * time.Second,
|
ExpectContinueTimeout: 1 * time.Second,
|
||||||
}
|
|
||||||
log.Infof("Using default network dialer for route %s (testing mode)", routeConfig.ID)
|
|
||||||
} else {
|
|
||||||
// Configure transport to use the provided connection (WireGuard, etc.)
|
|
||||||
proxy.Transport = &http.Transport{
|
|
||||||
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
|
|
||||||
log.Debugf("Using custom connection for route %s to %s", routeConfig.ID, address)
|
|
||||||
return routeConfig.Conn, nil
|
|
||||||
},
|
|
||||||
MaxIdleConns: 1,
|
|
||||||
MaxIdleConnsPerHost: 1,
|
|
||||||
IdleConnTimeout: 0, // Keep alive indefinitely
|
|
||||||
DisableKeepAlives: false,
|
|
||||||
TLSHandshakeTimeout: 10 * time.Second,
|
|
||||||
ExpectContinueTimeout: 1 * time.Second,
|
|
||||||
}
|
|
||||||
log.Infof("Using custom connection for route %s", routeConfig.ID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom error handler
|
// Custom error handler
|
||||||
|
|||||||
@@ -49,10 +49,9 @@ func New(config Config) (*Proxy, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
p := &Proxy{
|
p := &Proxy{
|
||||||
config: config,
|
config: config,
|
||||||
routes: make(map[string]*RouteConfig),
|
routes: make(map[string]*RouteConfig),
|
||||||
isRunning: false,
|
isRunning: false,
|
||||||
requestCallback: config.RequestDataCallback,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize OIDC handler if OIDC is configured
|
// Initialize OIDC handler if OIDC is configured
|
||||||
@@ -65,6 +64,13 @@ func New(config Config) (*Proxy, error) {
|
|||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetRequestCallback sets the callback for request metrics
|
||||||
|
func (p *Proxy) SetRequestCallback(callback RequestDataCallback) {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
p.requestCallback = callback
|
||||||
|
}
|
||||||
|
|
||||||
// GetConfig returns the proxy configuration
|
// GetConfig returns the proxy configuration
|
||||||
func (p *Proxy) GetConfig() Config {
|
func (p *Proxy) GetConfig() Config {
|
||||||
return p.config
|
return p.config
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
package reverseproxy
|
package reverseproxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/client/embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
clientStartupTimeout = 30 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddRoute adds a new route to the proxy
|
// AddRoute adds a new route to the proxy
|
||||||
@@ -20,8 +28,8 @@ func (p *Proxy) AddRoute(route *RouteConfig) error {
|
|||||||
if len(route.PathMappings) == 0 {
|
if len(route.PathMappings) == 0 {
|
||||||
return fmt.Errorf("route must have at least one path mapping")
|
return fmt.Errorf("route must have at least one path mapping")
|
||||||
}
|
}
|
||||||
if route.Conn == nil {
|
if route.SetupKey == "" {
|
||||||
return fmt.Errorf("route connection (Conn) is required")
|
return fmt.Errorf("route setup key is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
@@ -32,6 +40,19 @@ func (p *Proxy) AddRoute(route *RouteConfig) error {
|
|||||||
return fmt.Errorf("route for domain %s already exists", route.Domain)
|
return fmt.Errorf("route for domain %s already exists", route.Domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, err := embed.New(embed.Options{DeviceName: fmt.Sprintf("ingress-%s", route.ID), ManagementURL: p.config.ManagementURL, SetupKey: route.SetupKey})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create embedded client for route %s: %v", route.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, _ := context.WithTimeout(context.Background(), clientStartupTimeout)
|
||||||
|
err = client.Start(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to start embedded client for route %s: %v", route.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
route.nbClient = client
|
||||||
|
|
||||||
// Add route with domain as key
|
// Add route with domain as key
|
||||||
p.routes[route.Domain] = route
|
p.routes[route.Domain] = route
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"golang.org/x/crypto/acme/autocert"
|
"golang.org/x/crypto/acme/autocert"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Start starts the reverse proxy server
|
// Start starts the reverse proxy server (non-blocking)
|
||||||
func (p *Proxy) Start() error {
|
func (p *Proxy) Start() error {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
if p.isRunning {
|
if p.isRunning {
|
||||||
@@ -29,7 +29,7 @@ func (p *Proxy) Start() error {
|
|||||||
return p.startHTTP(handler)
|
return p.startHTTP(handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
// startHTTPS starts the proxy with HTTPS and Let's Encrypt
|
// startHTTPS starts the proxy with HTTPS and Let's Encrypt (non-blocking)
|
||||||
func (p *Proxy) startHTTPS(handler http.Handler) error {
|
func (p *Proxy) startHTTPS(handler http.Handler) error {
|
||||||
// Setup autocert manager with dynamic host policy
|
// Setup autocert manager with dynamic host policy
|
||||||
p.autocertManager = &autocert.Manager{
|
p.autocertManager = &autocert.Manager{
|
||||||
@@ -53,32 +53,36 @@ func (p *Proxy) startHTTPS(handler http.Handler) error {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Start HTTPS server
|
// Start HTTPS server in background
|
||||||
p.server = &http.Server{
|
p.server = &http.Server{
|
||||||
Addr: p.config.ListenAddress,
|
Addr: p.config.ListenAddress,
|
||||||
Handler: handler,
|
Handler: handler,
|
||||||
TLSConfig: p.autocertManager.TLSConfig(),
|
TLSConfig: p.autocertManager.TLSConfig(),
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Starting HTTPS reverse proxy server on %s", p.config.ListenAddress)
|
go func() {
|
||||||
if err := p.server.ListenAndServeTLS("", ""); err != nil && err != http.ErrServerClosed {
|
log.Infof("Starting HTTPS reverse proxy server on %s", p.config.ListenAddress)
|
||||||
return fmt.Errorf("HTTPS server failed: %w", err)
|
if err := p.server.ListenAndServeTLS("", ""); err != nil && err != http.ErrServerClosed {
|
||||||
}
|
log.Errorf("HTTPS server failed: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// startHTTP starts the proxy with HTTP only (no TLS)
|
// startHTTP starts the proxy with HTTP only (non-blocking)
|
||||||
func (p *Proxy) startHTTP(handler http.Handler) error {
|
func (p *Proxy) startHTTP(handler http.Handler) error {
|
||||||
p.server = &http.Server{
|
p.server = &http.Server{
|
||||||
Addr: p.config.HTTPListenAddress,
|
Addr: p.config.HTTPListenAddress,
|
||||||
Handler: handler,
|
Handler: handler,
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Starting HTTP reverse proxy server on %s (HTTPS disabled)", p.config.HTTPListenAddress)
|
go func() {
|
||||||
if err := p.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
log.Infof("Starting HTTP reverse proxy server on %s (HTTPS disabled)", p.config.HTTPListenAddress)
|
||||||
return fmt.Errorf("HTTP server failed: %w", err)
|
if err := p.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||||
}
|
log.Errorf("HTTP server failed: %w", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/caarlos0/env/v11"
|
"github.com/caarlos0/env/v11"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/proxy/internal/auth/oidc"
|
"github.com/netbirdio/netbird/proxy/internal/reverseproxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -48,9 +48,6 @@ func (d Duration) ToDuration() time.Duration {
|
|||||||
|
|
||||||
// Config holds the configuration for the reverse proxy server
|
// Config holds the configuration for the reverse proxy server
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// ListenAddress is the address the proxy server will listen on (e.g., ":443" or "0.0.0.0:443")
|
|
||||||
ListenAddress string `env:"NB_PROXY_LISTEN_ADDRESS" envDefault:":443" json:"listen_address"`
|
|
||||||
|
|
||||||
// ReadTimeout is the maximum duration for reading the entire request, including the body
|
// ReadTimeout is the maximum duration for reading the entire request, including the body
|
||||||
ReadTimeout time.Duration `env:"NB_PROXY_READ_TIMEOUT" envDefault:"30s" json:"read_timeout"`
|
ReadTimeout time.Duration `env:"NB_PROXY_READ_TIMEOUT" envDefault:"30s" json:"read_timeout"`
|
||||||
|
|
||||||
@@ -76,20 +73,7 @@ type Config struct {
|
|||||||
EnableGRPC bool `env:"NB_PROXY_ENABLE_GRPC" envDefault:"false" json:"enable_grpc"`
|
EnableGRPC bool `env:"NB_PROXY_ENABLE_GRPC" envDefault:"false" json:"enable_grpc"`
|
||||||
|
|
||||||
// Reverse Proxy Configuration
|
// Reverse Proxy Configuration
|
||||||
// HTTPListenAddress is the address for HTTP (default ":80")
|
ReverseProxy reverseproxy.Config `json:"reverse_proxy"`
|
||||||
HTTPListenAddress string `json:"http_listen_address"`
|
|
||||||
|
|
||||||
// EnableHTTPS enables automatic HTTPS with Let's Encrypt
|
|
||||||
EnableHTTPS bool `json:"enable_https"`
|
|
||||||
|
|
||||||
// TLSEmail is the email for Let's Encrypt registration
|
|
||||||
TLSEmail string `json:"tls_email"`
|
|
||||||
|
|
||||||
// CertCacheDir is the directory to cache certificates (default "./certs")
|
|
||||||
CertCacheDir string `json:"cert_cache_dir"`
|
|
||||||
|
|
||||||
// OIDCConfig is the global OIDC/OAuth configuration for authentication
|
|
||||||
OIDCConfig *oidc.Config `json:"oidc_config,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseAndLoad parses configuration from environment variables
|
// ParseAndLoad parses configuration from environment variables
|
||||||
@@ -138,11 +122,11 @@ func LoadFromFileOrEnv(configPath string) (Config, error) {
|
|||||||
return Config{}, fmt.Errorf("failed to load config from file: %w", err)
|
return Config{}, fmt.Errorf("failed to load config from file: %w", err)
|
||||||
}
|
}
|
||||||
cfg = fileCfg
|
cfg = fileCfg
|
||||||
}
|
} else {
|
||||||
|
// Parse environment variables (will override file config with any set env vars)
|
||||||
// Parse environment variables (will override file config with any set env vars)
|
if err := env.Parse(&cfg); err != nil {
|
||||||
if err := env.Parse(&cfg); err != nil {
|
return Config{}, fmt.Errorf("%w: %s", ErrFailedToParseConfig, err)
|
||||||
return Config{}, fmt.Errorf("%w: %s", ErrFailedToParseConfig, err)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cfg.Validate(); err != nil {
|
if err := cfg.Validate(); err != nil {
|
||||||
@@ -228,10 +212,6 @@ func (c *Config) UnmarshalJSON(data []byte) error {
|
|||||||
|
|
||||||
// Validate checks if the configuration is valid
|
// Validate checks if the configuration is valid
|
||||||
func (c *Config) Validate() error {
|
func (c *Config) Validate() error {
|
||||||
if c.ListenAddress == "" {
|
|
||||||
return errors.New("listen_address is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
validLogLevels := map[string]bool{
|
validLogLevels := map[string]bool{
|
||||||
"debug": true,
|
"debug": true,
|
||||||
"info": true,
|
"info": true,
|
||||||
|
|||||||
@@ -86,33 +86,24 @@ func NewServer(config Config) (*Server, error) {
|
|||||||
exposedServices: make(map[string]*ExposedServiceConfig),
|
exposedServices: make(map[string]*ExposedServiceConfig),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set defaults for reverse proxy config if not provided
|
// Create reverse proxy using embedded config
|
||||||
httpListenAddr := config.HTTPListenAddress
|
proxy, err := reverseproxy.New(config.ReverseProxy)
|
||||||
if httpListenAddr == "" {
|
if err != nil {
|
||||||
httpListenAddr = ":54321" // Use port 54321 for local testing
|
return nil, fmt.Errorf("failed to create reverse proxy: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create reverse proxy with request callback
|
// Set request data callback
|
||||||
proxyConfig := reverseproxy.Config{
|
proxy.SetRequestCallback(func(data reverseproxy.RequestData) {
|
||||||
HTTPListenAddress: httpListenAddr,
|
log.WithFields(log.Fields{
|
||||||
EnableHTTPS: config.EnableHTTPS,
|
"service_id": data.ServiceID,
|
||||||
TLSEmail: config.TLSEmail,
|
"host": data.Host,
|
||||||
CertCacheDir: config.CertCacheDir,
|
"method": data.Method,
|
||||||
RequestDataCallback: func(data reverseproxy.RequestData) {
|
"path": data.Path,
|
||||||
log.WithFields(log.Fields{
|
"response_code": data.ResponseCode,
|
||||||
"service_id": data.ServiceID,
|
"duration_ms": data.DurationMs,
|
||||||
"host": data.Host,
|
"source_ip": data.SourceIP,
|
||||||
"method": data.Method,
|
}).Info("Access log received")
|
||||||
"path": data.Path,
|
})
|
||||||
"response_code": data.ResponseCode,
|
|
||||||
"duration_ms": data.DurationMs,
|
|
||||||
"source_ip": data.SourceIP,
|
|
||||||
}).Info("Access log received")
|
|
||||||
},
|
|
||||||
// Use global OIDC configuration from config
|
|
||||||
OIDCConfig: config.OIDCConfig,
|
|
||||||
}
|
|
||||||
proxy, err := reverseproxy.New(proxyConfig)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create reverse proxy: %w", err)
|
return nil, fmt.Errorf("failed to create reverse proxy: %w", err)
|
||||||
}
|
}
|
||||||
@@ -140,7 +131,7 @@ func (s *Server) Start() error {
|
|||||||
s.isRunning = true
|
s.isRunning = true
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
|
|
||||||
log.Infof("Starting proxy reverse proxy server on %s", s.config.ListenAddress)
|
log.Infof("Starting proxy reverse proxy server on %s", s.config.ReverseProxy.ListenAddress)
|
||||||
|
|
||||||
// Start reverse proxy
|
// Start reverse proxy
|
||||||
if err := s.proxy.Start(); err != nil {
|
if err := s.proxy.Start(); err != nil {
|
||||||
@@ -185,9 +176,9 @@ func (s *Server) Start() error {
|
|||||||
&reverseproxy.RouteConfig{
|
&reverseproxy.RouteConfig{
|
||||||
ID: "test",
|
ID: "test",
|
||||||
Domain: "test.netbird.io",
|
Domain: "test.netbird.io",
|
||||||
PathMappings: map[string]string{"/": "localhost:8080"},
|
PathMappings: map[string]string{"/": "localhost:8181"},
|
||||||
Conn: reverseproxy.NewDefaultConn(),
|
|
||||||
AuthConfig: testAuthConfig,
|
AuthConfig: testAuthConfig,
|
||||||
|
SetupKey: "setup-key",
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
log.Warn("Failed to add test route: ", err)
|
log.Warn("Failed to add test route: ", err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user