mirror of
https://github.com/juanfont/headscale.git
synced 2026-02-07 20:04:00 +01:00
feat: reload certificate on sighup reload
This commit is contained in:
parent
20dff82f95
commit
3f5eb0854d
@ -102,6 +102,11 @@ type Headscale struct {
|
||||
mapBatcher mapper.Batcher
|
||||
|
||||
clientStreamsOpen sync.WaitGroup
|
||||
|
||||
// TLS certificate for manual TLS configuration (non-ACME).
|
||||
// Protected by tlsCertMu for concurrent access during SIGHUP reload.
|
||||
tlsCertMu sync.RWMutex
|
||||
tlsCert *tls.Certificate
|
||||
}
|
||||
|
||||
var (
|
||||
@ -823,20 +828,25 @@ func (h *Headscale) Serve() error {
|
||||
case syscall.SIGHUP:
|
||||
log.Info().
|
||||
Str("signal", sig.String()).
|
||||
Msg("Received SIGHUP, reloading ACL policy")
|
||||
Msg("Received SIGHUP, reloading configuration")
|
||||
|
||||
if h.cfg.Policy.IsEmpty() {
|
||||
continue
|
||||
// Reload TLS certificate if using manual TLS (not ACME/Let's Encrypt)
|
||||
if h.cfg.TLS.CertPath != "" && h.cfg.TLS.LetsEncrypt.Hostname == "" {
|
||||
if err := h.reloadTLSCertificate(); err != nil {
|
||||
log.Error().Err(err).Msg("reloading TLS certificate")
|
||||
}
|
||||
}
|
||||
|
||||
changes, err := h.state.ReloadPolicy()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("reloading policy")
|
||||
continue
|
||||
// Reload ACL policy
|
||||
if !h.cfg.Policy.IsEmpty() {
|
||||
changes, err := h.state.ReloadPolicy()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("reloading ACL policy")
|
||||
} else {
|
||||
h.Change(changes...)
|
||||
}
|
||||
}
|
||||
|
||||
h.Change(changes...)
|
||||
|
||||
default:
|
||||
info := func(msg string) { log.Info().Msg(msg) }
|
||||
|
||||
@ -995,17 +1005,49 @@ func (h *Headscale) getTLSSettings() (*tls.Config, error) {
|
||||
}
|
||||
|
||||
tlsConfig := &tls.Config{
|
||||
NextProtos: []string{"http/1.1"},
|
||||
Certificates: make([]tls.Certificate, 1),
|
||||
MinVersion: tls.VersionTLS12,
|
||||
NextProtos: []string{"http/1.1"},
|
||||
MinVersion: tls.VersionTLS12,
|
||||
}
|
||||
|
||||
tlsConfig.Certificates[0], err = tls.LoadX509KeyPair(h.cfg.TLS.CertPath, h.cfg.TLS.KeyPath)
|
||||
if err := h.reloadTLSCertificate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tlsConfig, err
|
||||
tlsConfig.GetCertificate = h.getTLSCertificate
|
||||
|
||||
return tlsConfig, nil
|
||||
}
|
||||
}
|
||||
|
||||
// reloadTLSCertificate loads or reloads the TLS certificate from disk.
|
||||
// This is called on startup and on SIGHUP for certificate rotation.
|
||||
func (h *Headscale) reloadTLSCertificate() error {
|
||||
cert, err := tls.LoadX509KeyPair(h.cfg.TLS.CertPath, h.cfg.TLS.KeyPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("loading TLS certificate: %w", err)
|
||||
}
|
||||
|
||||
h.tlsCertMu.Lock()
|
||||
h.tlsCert = &cert
|
||||
h.tlsCertMu.Unlock()
|
||||
|
||||
log.Info().
|
||||
Str("cert_path", h.cfg.TLS.CertPath).
|
||||
Str("key_path", h.cfg.TLS.KeyPath).
|
||||
Msg("TLS certificate loaded")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getTLSCertificate returns the current TLS certificate.
|
||||
// It implements the tls.Config.GetCertificate callback signature.
|
||||
func (h *Headscale) getTLSCertificate(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
h.tlsCertMu.RLock()
|
||||
defer h.tlsCertMu.RUnlock()
|
||||
|
||||
return h.tlsCert, nil
|
||||
}
|
||||
|
||||
func readOrCreatePrivateKey(path string) (*key.MachinePrivate, error) {
|
||||
dir := filepath.Dir(path)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user