[signal] Fix HTTP/WebSocket proxy not using custom certificates (#4644)

This pull request fixes a bug where the HTTP/WebSocket proxy server was not using custom TLS certificates when provided via --cert-file and --cert-key flags. Previously, only the gRPC server had TLS enabled with custom certificates, while the HTTP/WebSocket proxy ran without TLS.
This commit is contained in:
Bethuel Mmbaga
2025-10-24 15:40:20 +03:00
committed by GitHub
parent 6654e2dbf7
commit 709e24eb6f
3 changed files with 24 additions and 12 deletions

View File

@@ -185,12 +185,15 @@ if [[ "$NETBIRD_DISABLE_LETSENCRYPT" == "true" ]]; then
echo "You are also free to remove any occurrences of the Letsencrypt-volume $LETSENCRYPT_VOLUMENAME" echo "You are also free to remove any occurrences of the Letsencrypt-volume $LETSENCRYPT_VOLUMENAME"
echo "" echo ""
export NETBIRD_SIGNAL_PROTOCOL="https"
unset NETBIRD_LETSENCRYPT_DOMAIN unset NETBIRD_LETSENCRYPT_DOMAIN
unset NETBIRD_MGMT_API_CERT_FILE unset NETBIRD_MGMT_API_CERT_FILE
unset NETBIRD_MGMT_API_CERT_KEY_FILE unset NETBIRD_MGMT_API_CERT_KEY_FILE
fi fi
if [[ -n "$NETBIRD_MGMT_API_CERT_FILE" && -n "$NETBIRD_MGMT_API_CERT_KEY_FILE" ]]; then
export NETBIRD_SIGNAL_PROTOCOL="https"
fi
# Check if management identity provider is set # Check if management identity provider is set
if [ -n "$NETBIRD_MGMT_IDP" ]; then if [ -n "$NETBIRD_MGMT_IDP" ]; then
EXTRA_CONFIG={} EXTRA_CONFIG={}

View File

@@ -40,13 +40,21 @@ services:
signal: signal:
<<: *default <<: *default
image: netbirdio/signal:$NETBIRD_SIGNAL_TAG image: netbirdio/signal:$NETBIRD_SIGNAL_TAG
depends_on:
- dashboard
volumes: volumes:
- $SIGNAL_VOLUMENAME:/var/lib/netbird - $SIGNAL_VOLUMENAME:/var/lib/netbird
- $LETSENCRYPT_VOLUMENAME:/etc/letsencrypt:ro
ports: ports:
- $NETBIRD_SIGNAL_PORT:80 - $NETBIRD_SIGNAL_PORT:80
# # port and command for Let's Encrypt validation # # port and command for Let's Encrypt validation
# - 443:443 # - 443:443
# command: ["--letsencrypt-domain", "$NETBIRD_LETSENCRYPT_DOMAIN", "--log-file", "console"] # command: ["--letsencrypt-domain", "$NETBIRD_LETSENCRYPT_DOMAIN", "--log-file", "console"]
command: [
"--cert-file", "$NETBIRD_MGMT_API_CERT_FILE",
"--cert-key", "$NETBIRD_MGMT_API_CERT_KEY_FILE",
"--log-file", "console"
]
# Relay # Relay
relay: relay:

View File

@@ -94,7 +94,7 @@ var (
startPprof() startPprof()
opts, certManager, err := getTLSConfigurations() opts, certManager, tlsConfig, err := getTLSConfigurations()
if err != nil { if err != nil {
return err return err
} }
@@ -132,7 +132,7 @@ var (
// Start the main server - always serve HTTP with WebSocket proxy support // Start the main server - always serve HTTP with WebSocket proxy support
// If certManager is configured and signalPort == 443, it's already handled by startServerWithCertManager // If certManager is configured and signalPort == 443, it's already handled by startServerWithCertManager
if certManager == nil { if tlsConfig == nil {
// Without TLS, serve plain HTTP // Without TLS, serve plain HTTP
httpListener, err = net.Listen("tcp", fmt.Sprintf(":%d", signalPort)) httpListener, err = net.Listen("tcp", fmt.Sprintf(":%d", signalPort))
if err != nil { if err != nil {
@@ -140,9 +140,10 @@ var (
} }
log.Infof("running HTTP server with WebSocket proxy (no TLS): %s", httpListener.Addr().String()) log.Infof("running HTTP server with WebSocket proxy (no TLS): %s", httpListener.Addr().String())
serveHTTP(httpListener, grpcRootHandler) serveHTTP(httpListener, grpcRootHandler)
} else if signalPort != 443 { } else if certManager == nil || signalPort != 443 {
// With TLS but not on port 443, serve HTTPS // Serve HTTPS if not already handled by startServerWithCertManager
httpListener, err = tls.Listen("tcp", fmt.Sprintf(":%d", signalPort), certManager.TLSConfig()) // (custom certificates or Let's Encrypt with custom port)
httpListener, err = tls.Listen("tcp", fmt.Sprintf(":%d", signalPort), tlsConfig)
if err != nil { if err != nil {
return err return err
} }
@@ -202,7 +203,7 @@ func startPprof() {
}() }()
} }
func getTLSConfigurations() ([]grpc.ServerOption, *autocert.Manager, error) { func getTLSConfigurations() ([]grpc.ServerOption, *autocert.Manager, *tls.Config, error) {
var ( var (
err error err error
certManager *autocert.Manager certManager *autocert.Manager
@@ -211,33 +212,33 @@ func getTLSConfigurations() ([]grpc.ServerOption, *autocert.Manager, error) {
if signalLetsencryptDomain == "" && signalCertFile == "" && signalCertKey == "" { if signalLetsencryptDomain == "" && signalCertFile == "" && signalCertKey == "" {
log.Infof("running without TLS") log.Infof("running without TLS")
return nil, nil, nil return nil, nil, nil, nil
} }
if signalLetsencryptDomain != "" { if signalLetsencryptDomain != "" {
certManager, err = encryption.CreateCertManager(signalSSLDir, signalLetsencryptDomain) certManager, err = encryption.CreateCertManager(signalSSLDir, signalLetsencryptDomain)
if err != nil { if err != nil {
return nil, certManager, err return nil, certManager, nil, err
} }
tlsConfig = certManager.TLSConfig() tlsConfig = certManager.TLSConfig()
log.Infof("setting up TLS with LetsEncrypt.") log.Infof("setting up TLS with LetsEncrypt.")
} else { } else {
if signalCertFile == "" || signalCertKey == "" { if signalCertFile == "" || signalCertKey == "" {
log.Errorf("both cert-file and cert-key must be provided when not using LetsEncrypt") log.Errorf("both cert-file and cert-key must be provided when not using LetsEncrypt")
return nil, certManager, errors.New("both cert-file and cert-key must be provided when not using LetsEncrypt") return nil, certManager, nil, errors.New("both cert-file and cert-key must be provided when not using LetsEncrypt")
} }
tlsConfig, err = loadTLSConfig(signalCertFile, signalCertKey) tlsConfig, err = loadTLSConfig(signalCertFile, signalCertKey)
if err != nil { if err != nil {
log.Errorf("cannot load TLS credentials: %v", err) log.Errorf("cannot load TLS credentials: %v", err)
return nil, certManager, err return nil, certManager, nil, err
} }
log.Infof("setting up TLS with custom certificates.") log.Infof("setting up TLS with custom certificates.")
} }
transportCredentials := credentials.NewTLS(tlsConfig) transportCredentials := credentials.NewTLS(tlsConfig)
return []grpc.ServerOption{grpc.Creds(transportCredentials)}, certManager, err return []grpc.ServerOption{grpc.Creds(transportCredentials)}, certManager, tlsConfig, err
} }
func startServerWithCertManager(certManager *autocert.Manager, grpcRootHandler http.Handler) { func startServerWithCertManager(certManager *autocert.Manager, grpcRootHandler http.Handler) {