diff --git a/combined/cmd/root.go b/combined/cmd/root.go index 3e583ef20..917312e57 100644 --- a/combined/cmd/root.go +++ b/combined/cmd/root.go @@ -205,7 +205,7 @@ func createAllServers(ctx context.Context, cfg *CombinedConfig) (*serverInstance metricsServer: metricsServer, } - _, tlsSupport, err := handleTLSConfig(cfg) + tlsConfig, tlsSupport, err := handleTLSConfig(cfg) if err != nil { return nil, fmt.Errorf("failed to setup TLS config: %w", err) } @@ -214,7 +214,7 @@ func createAllServers(ctx context.Context, cfg *CombinedConfig) (*serverInstance return nil, err } - if err := servers.createManagementServer(ctx, cfg); err != nil { + if err := servers.createManagementServer(ctx, cfg, tlsConfig); err != nil { return nil, err } @@ -264,7 +264,7 @@ func (s *serverInstances) createRelayServer(cfg *CombinedConfig, tlsSupport bool return nil } -func (s *serverInstances) createManagementServer(ctx context.Context, cfg *CombinedConfig) error { +func (s *serverInstances) createManagementServer(ctx context.Context, cfg *CombinedConfig, tlsConfig *tls.Config) error { if !cfg.Management.Enabled { return nil } @@ -297,7 +297,7 @@ func (s *serverInstances) createManagementServer(ctx context.Context, cfg *Combi LogConfigInfo(mgmtConfig) - s.mgmtSrv, err = createManagementServer(cfg, mgmtConfig) + s.mgmtSrv, err = createManagementServer(cfg, mgmtConfig, tlsConfig) if err != nil { cleanupSTUNListeners(s.stunListeners) return fmt.Errorf("failed to create management server: %w", err) @@ -513,7 +513,7 @@ func handleTLSConfig(cfg *CombinedConfig) (*tls.Config, bool, error) { return nil, false, nil } -func createManagementServer(cfg *CombinedConfig, mgmtConfig *nbconfig.Config) (mgmtServer.Server, error) { +func createManagementServer(cfg *CombinedConfig, mgmtConfig *nbconfig.Config, tlsConfig *tls.Config) (mgmtServer.Server, error) { mgmt := cfg.Management // Extract port from listen address @@ -542,6 +542,7 @@ func createManagementServer(cfg *CombinedConfig, mgmtConfig *nbconfig.Config) (m AutoResolveDomains: true, MgmtPort: mgmtPort, MgmtMetricsPort: cfg.Server.MetricsPort, + TLSConfig: tlsConfig, DisableMetrics: mgmt.DisableAnonymousMetrics, DisableGeoliteUpdate: mgmt.DisableGeoliteUpdate, // Always enable user deletion from IDP in combined server (embedded IdP is always enabled) diff --git a/management/internals/server/server.go b/management/internals/server/server.go index 22a61bada..9709d1099 100644 --- a/management/internals/server/server.go +++ b/management/internals/server/server.go @@ -74,6 +74,7 @@ type BaseServer struct { grpcExtensions []GRPCExtension listener net.Listener + tlsConfig *tls.Config certManager *autocert.Manager update *version.Update @@ -94,6 +95,7 @@ type Config struct { DisableGeoliteUpdate bool UserDeleteFromIDPEnabled bool AutoResolveDomains bool + TLSConfig *tls.Config } // NewServer initializes and configures a new Server instance @@ -110,6 +112,7 @@ func NewServer(cfg *Config) *BaseServer { disableLegacyManagementPort: cfg.DisableLegacyManagementPort, mgmtMetricsPort: cfg.MgmtMetricsPort, autoResolveDomains: cfg.AutoResolveDomains, + tlsConfig: cfg.TLSConfig, } s.container[ContainerKeyBaseServer] = s @@ -139,21 +142,9 @@ func (s *BaseServer) Start(ctx context.Context) error { } s.EphemeralManager().LoadInitialPeers(srvCtx) - var tlsConfig *tls.Config - tlsEnabled := false - if s.Config.HttpConfig.LetsEncryptDomain != "" { - s.certManager, err = encryption.CreateCertManager(s.Config.Datadir, s.Config.HttpConfig.LetsEncryptDomain) - if err != nil { - return fmt.Errorf("failed creating LetsEncrypt cert manager: %v", err) - } - tlsEnabled = true - } else if s.Config.HttpConfig.CertFile != "" && s.Config.HttpConfig.CertKey != "" { - tlsConfig, err = loadTLSConfig(s.Config.HttpConfig.CertFile, s.Config.HttpConfig.CertKey) - if err != nil { - log.WithContext(srvCtx).Errorf("cannot load TLS credentials: %v", err) - return err - } - tlsEnabled = true + tlsEnabled, err := s.setupTLS(srvCtx) + if err != nil { + return err } installationID, err := getInstallationID(srvCtx, s.Store()) @@ -215,8 +206,8 @@ func (s *BaseServer) Start(ctx context.Context) error { log.WithContext(ctx).Infof("running HTTP server (LetsEncrypt challenge handler): %s", cml.Addr().String()) s.serveHTTP(ctx, cml, s.certManager.HTTPHandler(nil)) } - case tlsConfig != nil: - s.listener, err = tls.Listen("tcp", fmt.Sprintf(":%d", s.mgmtPort), tlsConfig) + case s.tlsConfig != nil: + s.listener, err = tls.Listen("tcp", fmt.Sprintf(":%d", s.mgmtPort), s.tlsConfig) if err != nil { return fmt.Errorf("failed creating TLS listener on port %d: %v", s.mgmtPort, err) } @@ -240,6 +231,31 @@ func (s *BaseServer) Start(ctx context.Context) error { return nil } +// setupTLS resolves the listener's TLS source: an injected config wins over the HttpConfig certificate settings +func (s *BaseServer) setupTLS(ctx context.Context) (bool, error) { + switch { + case s.tlsConfig != nil: + return true, nil + case s.Config.HttpConfig.LetsEncryptDomain != "": + certManager, err := encryption.CreateCertManager(s.Config.Datadir, s.Config.HttpConfig.LetsEncryptDomain) + if err != nil { + return false, fmt.Errorf("failed creating LetsEncrypt cert manager: %v", err) + } + s.certManager = certManager + return true, nil + case s.Config.HttpConfig.CertFile != "" && s.Config.HttpConfig.CertKey != "": + tlsConfig, err := loadTLSConfig(s.Config.HttpConfig.CertFile, s.Config.HttpConfig.CertKey) + if err != nil { + log.WithContext(ctx).Errorf("cannot load TLS credentials: %v", err) + return false, err + } + s.tlsConfig = tlsConfig + return true, nil + default: + return false, nil + } +} + // Stop attempts a graceful shutdown, waiting up to 5 seconds for active connections to finish func (s *BaseServer) Stop() error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)