mirror of
https://github.com/gogrlx/nats-server.git
synced 2026-04-02 03:38:42 -07:00
[FIXED] Websocket: TLS configuration not updated on reload
Although we do not support websocket configuration changes, we usually try to support changes to TLS certificates, etc.. The way websocket is handled (using an http server), the TLS config was given on startup and updates following a configuration reload would not be reflected. Using a tls.Config function that allows passing the tls config prior to handshake seem to workaround this issue. I have added a test that demonstrate that the TLS configuration is really updated after the reload. Signed-off-by: Ivan Kozlovic <ivan@synadia.com>
This commit is contained in:
@@ -955,6 +955,7 @@ func (s *Server) startWebsocketServer() {
|
||||
if o.TLSConfig != nil {
|
||||
proto = wsSchemePrefixTLS
|
||||
config := o.TLSConfig.Clone()
|
||||
config.GetConfigForClient = s.wsGetTLSConfig
|
||||
hl, err = tls.Listen("tcp", hp, config)
|
||||
} else {
|
||||
proto = wsSchemePrefix
|
||||
@@ -1028,6 +1029,17 @@ func (s *Server) startWebsocketServer() {
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
// The TLS configuration is passed to the listener when the websocket
|
||||
// "server" is setup. That prevents TLS configuration updates on reload
|
||||
// from being used. By setting this function in tls.Config.GetConfigForClient
|
||||
// we instruct the TLS handshake to ask for the tls configuration to be
|
||||
// used for a specific client. We don't care which client, we always use
|
||||
// the same TLS configuration.
|
||||
func (s *Server) wsGetTLSConfig(_ *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
opts := s.getOpts()
|
||||
return opts.Websocket.TLSConfig, nil
|
||||
}
|
||||
|
||||
// This is similar to createClient() but has some modifications
|
||||
// specific to handle websocket clients.
|
||||
// The comments have been kept to minimum to reduce code size.
|
||||
|
||||
@@ -3643,7 +3643,63 @@ func TestWSJWTCookieUser(t *testing.T) {
|
||||
})
|
||||
}
|
||||
s.Shutdown()
|
||||
}
|
||||
|
||||
func TestWSReloadTLSConfig(t *testing.T) {
|
||||
template := `
|
||||
listen: "127.0.0.1:-1"
|
||||
websocket {
|
||||
listen: "127.0.0.1:-1"
|
||||
tls {
|
||||
cert_file: '%s'
|
||||
key_file: '%s'
|
||||
ca_file: '../test/configs/certs/ca.pem'
|
||||
}
|
||||
}
|
||||
`
|
||||
conf := createConfFile(t, []byte(fmt.Sprintf(template,
|
||||
"../test/configs/certs/server-noip.pem",
|
||||
"../test/configs/certs/server-key-noip.pem")))
|
||||
defer removeFile(t, conf)
|
||||
|
||||
s, o := RunServerWithConfig(conf)
|
||||
defer s.Shutdown()
|
||||
|
||||
addr := fmt.Sprintf("127.0.0.1:%d", o.Websocket.Port)
|
||||
wsc, err := net.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating ws connection: %v", err)
|
||||
}
|
||||
defer wsc.Close()
|
||||
|
||||
tc := &TLSConfigOpts{CaFile: "../test/configs/certs/ca.pem"}
|
||||
tlsConfig, err := GenTLSConfig(tc)
|
||||
if err != nil {
|
||||
t.Fatalf("Error generating TLS config: %v", err)
|
||||
}
|
||||
tlsConfig.ServerName = "127.0.0.1"
|
||||
tlsConfig.RootCAs = tlsConfig.ClientCAs
|
||||
tlsConfig.ClientCAs = nil
|
||||
wsc = tls.Client(wsc, tlsConfig.Clone())
|
||||
if err := wsc.(*tls.Conn).Handshake(); err == nil || !strings.Contains(err.Error(), "SAN") {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
wsc.Close()
|
||||
|
||||
reloadUpdateConfig(t, s, conf, fmt.Sprintf(template,
|
||||
"../test/configs/certs/server-cert.pem",
|
||||
"../test/configs/certs/server-key.pem"))
|
||||
|
||||
wsc, err = net.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating ws connection: %v", err)
|
||||
}
|
||||
defer wsc.Close()
|
||||
|
||||
wsc = tls.Client(wsc, tlsConfig.Clone())
|
||||
if err := wsc.(*tls.Conn).Handshake(); err != nil {
|
||||
t.Fatalf("Error on TLS handshake: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// ==================================================================
|
||||
|
||||
Reference in New Issue
Block a user