Files
netbird/signal/cmd/run_test.go
T
Nicolas Frati a5834fdaab [management,signal] Make the Let's Encrypt challenge listener address configurable (#7706)
* [management,signal] Make the Let's Encrypt challenge listener address configurable

With Let's Encrypt enabled and --port set to something other than 443,
signal and management also opened a separate challenge listener that was
hard-coded to :443. Non-root deployments, such as the UBI images, could
not start that listener.

Add --letsencrypt-listen-address to both. It defaults to :443, so current
behavior is unchanged. An empty value disables the separate listener for
setups that forward public port 443 to --port, where the main TLS
listener already answers TLS-ALPN-01 challenges.

Signal now fails on startup when the challenge listener cannot bind, and
exits non-zero when a server stops unexpectedly instead of exiting 0. A
failure reported before the run loop waited was previously dropped.
Management no longer opens a new :443 listener on shutdown just to close it.

* [management,signal] Keep the challenge listener change additive

Remove the Signal fail-fast changes from this PR. They change the
behavior that existing installations see after an upgrade, so they move
to a separate PR.

If the challenge listener cannot bind, Signal now logs the error and
continues. The main TLS listener still answers TLS-ALPN-01 challenges.
Management keeps its previous behavior and stops with an error.

The check for an empty address moves to the caller, so the function
does not return a nil listener with a nil error. Also add assertion
messages, guard a nil listener in a test cleanup, and add the flag to
the Signal README.
2026-10-09 13:37:25 +02:00

53 lines
1.7 KiB
Go

package cmd
import (
"net"
"net/http"
"testing"
"time"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/acme"
"golang.org/x/crypto/acme/autocert"
)
func setLetsencryptListen(t *testing.T, port int, address string) {
t.Helper()
oldPort, oldAddress := signalPort, signalLetsencryptListen
signalPort, signalLetsencryptListen = port, address
t.Cleanup(func() {
signalPort, signalLetsencryptListen = oldPort, oldAddress
})
}
func TestStartServerWithCertManager_CustomAddress(t *testing.T) {
setLetsencryptListen(t, 10000, "127.0.0.1:0")
listener, err := startServerWithCertManager(&autocert.Manager{}, http.NotFoundHandler())
require.NoError(t, err)
require.NotNil(t, listener, "challenge listener should be created on the configured address")
t.Cleanup(func() { _ = listener.Close() })
conn, err := net.DialTimeout("tcp", listener.Addr().String(), time.Second)
require.NoError(t, err)
require.NoError(t, conn.Close())
}
func TestStartServerWithCertManager_BindFailure(t *testing.T) {
occupied, err := net.Listen("tcp", "127.0.0.1:0")
require.NoError(t, err)
t.Cleanup(func() { _ = occupied.Close() })
setLetsencryptListen(t, 10000, occupied.Addr().String())
listener, err := startServerWithCertManager(&autocert.Manager{}, http.NotFoundHandler())
require.Error(t, err)
require.Nil(t, listener, "no listener should be returned when the bind fails")
}
func TestCertManagerTLSConfigAnswersTLSALPN01(t *testing.T) {
// Disabling the separate listener relies on the main listener answering
// TLS-ALPN-01 challenges through the cert manager's TLS config.
cfg := (&autocert.Manager{}).TLSConfig()
require.Contains(t, cfg.NextProtos, acme.ALPNProto, "cert manager TLS config should offer the ACME TLS-ALPN protocol")
}