refactor: embedded DERP no longer verify clients via HTTP

- register the `headscale://` protocol in `http.DefaultTransport` to intercept network requests
- update configuration to use a single boolean option `verify_clients`
This commit is contained in:
seiuneko 2024-11-28 22:44:35 +08:00
parent 55980d6427
commit 1541fa4d8a
No known key found for this signature in database
GPG Key ID: A5A75952899A0179
4 changed files with 27 additions and 14 deletions

View File

@ -87,11 +87,8 @@ derp:
region_code: "headscale" region_code: "headscale"
region_name: "Headscale Embedded DERP" region_name: "Headscale Embedded DERP"
# If non-empty, an admission controller URL for permitting client connections # Verify clients to this DERP server using the Headscale node list
verify_client_url: "http://127.0.0.1:8080/verify" verify_clients: true
# Whether derp fail open if verify_client_url is unreachable
verify_client_url_fail_open: false
# Listens over UDP at the configured address for STUN connections - to help with NAT traversal. # Listens over UDP at the configured address for STUN connections - to help with NAT traversal.
# When the embedded DERP server is enabled stun_listen_addr MUST be defined. # When the embedded DERP server is enabled stun_listen_addr MUST be defined.

View File

@ -221,6 +221,7 @@ func NewHeadscale(cfg *types.Config) (*Headscale, error) {
embeddedDERPServer, err := derpServer.NewDERPServer( embeddedDERPServer, err := derpServer.NewDERPServer(
cfg.ServerURL, cfg.ServerURL,
app.VerifyHandler,
key.NodePrivate(*derpServerKey), key.NodePrivate(*derpServerKey),
&cfg.DERP, &cfg.DERP,
) )

View File

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
"net/http/httptest"
"net/netip" "net/netip"
"net/url" "net/url"
"strconv" "strconv"
@ -39,14 +40,20 @@ type DERPServer struct {
func NewDERPServer( func NewDERPServer(
serverURL string, serverURL string,
verifyHandler func(writer http.ResponseWriter, req *http.Request),
derpKey key.NodePrivate, derpKey key.NodePrivate,
cfg *types.DERPConfig, cfg *types.DERPConfig,
) (*DERPServer, error) { ) (*DERPServer, error) {
log.Trace().Caller().Msg("Creating new embedded DERP server") log.Trace().Caller().Msg("Creating new embedded DERP server")
server := derp.NewServer(derpKey, util.TSLogfWrapper()) // nolint // zerolinter complains server := derp.NewServer(derpKey, util.TSLogfWrapper()) // nolint // zerolinter complains
if cfg.ServerVerifyClientURL != "" {
server.SetVerifyClientURL(cfg.ServerVerifyClientURL) if cfg.ServerVerifyClients {
server.SetVerifyClientURLFailOpen(cfg.ServerVerifyFailOpen) t := http.DefaultTransport.(*http.Transport)
t.RegisterProtocol("headscale", &HeadscaleTransport{
verifyHandler: verifyHandler,
})
server.SetVerifyClientURL("headscale://verify")
server.SetVerifyClientURLFailOpen(false)
} }
return &DERPServer{ return &DERPServer{
@ -364,3 +371,14 @@ func serverSTUNListener(ctx context.Context, packetConn *net.UDPConn) {
} }
} }
} }
type HeadscaleTransport struct {
verifyHandler func(writer http.ResponseWriter, req *http.Request)
}
func (t *HeadscaleTransport) RoundTrip(req *http.Request) (*http.Response, error) {
recorder := httptest.NewRecorder()
t.verifyHandler(recorder, req)
resp := recorder.Result()
return resp, nil
}

View File

@ -185,8 +185,7 @@ type DERPConfig struct {
ServerRegionCode string ServerRegionCode string
ServerRegionName string ServerRegionName string
ServerPrivateKeyPath string ServerPrivateKeyPath string
ServerVerifyClientURL string ServerVerifyClients bool
ServerVerifyFailOpen bool
STUNAddr string STUNAddr string
URLs []url.URL URLs []url.URL
Paths []string Paths []string
@ -433,8 +432,7 @@ func derpConfig() DERPConfig {
serverRegionID := viper.GetInt("derp.server.region_id") serverRegionID := viper.GetInt("derp.server.region_id")
serverRegionCode := viper.GetString("derp.server.region_code") serverRegionCode := viper.GetString("derp.server.region_code")
serverRegionName := viper.GetString("derp.server.region_name") serverRegionName := viper.GetString("derp.server.region_name")
serverVerifyClientURL := viper.GetString("derp.server.verify_client_url") serverVerifyClients := viper.GetBool("derp.server.verify_clients")
serverVerifyFailOpen := viper.GetBool("derp.server.verify_client_url_fail_open")
stunAddr := viper.GetString("derp.server.stun_listen_addr") stunAddr := viper.GetString("derp.server.stun_listen_addr")
privateKeyPath := util.AbsolutePathFromConfigPath( privateKeyPath := util.AbsolutePathFromConfigPath(
viper.GetString("derp.server.private_key_path"), viper.GetString("derp.server.private_key_path"),
@ -479,8 +477,7 @@ func derpConfig() DERPConfig {
ServerRegionID: serverRegionID, ServerRegionID: serverRegionID,
ServerRegionCode: serverRegionCode, ServerRegionCode: serverRegionCode,
ServerRegionName: serverRegionName, ServerRegionName: serverRegionName,
ServerVerifyClientURL: serverVerifyClientURL, ServerVerifyClients: serverVerifyClients,
ServerVerifyFailOpen: serverVerifyFailOpen,
ServerPrivateKeyPath: privateKeyPath, ServerPrivateKeyPath: privateKeyPath,
STUNAddr: stunAddr, STUNAddr: stunAddr,
URLs: urls, URLs: urls,