diff --git a/app.go b/app.go index 9b92fd3b..c835013e 100644 --- a/app.go +++ b/app.go @@ -689,7 +689,7 @@ func (h *Headscale) Serve() error { func (h *Headscale) getTLSSettings() (*tls.Config, error) { var err error - if h.cfg.TLSLetsEncryptHostname != "" { + if h.cfg.TLS.LetsEncrypt.Hostname != "" { if !strings.HasPrefix(h.cfg.ServerURL, "https://") { log.Warn(). Msg("Listening with TLS but ServerURL does not start with https://") @@ -697,15 +697,15 @@ func (h *Headscale) getTLSSettings() (*tls.Config, error) { certManager := autocert.Manager{ Prompt: autocert.AcceptTOS, - HostPolicy: autocert.HostWhitelist(h.cfg.TLSLetsEncryptHostname), - Cache: autocert.DirCache(h.cfg.TLSLetsEncryptCacheDir), + HostPolicy: autocert.HostWhitelist(h.cfg.TLS.LetsEncrypt.Hostname), + Cache: autocert.DirCache(h.cfg.TLS.LetsEncrypt.CacheDir), Client: &acme.Client{ DirectoryURL: h.cfg.ACMEURL, }, Email: h.cfg.ACMEEmail, } - switch h.cfg.TLSLetsEncryptChallengeType { + switch h.cfg.TLS.LetsEncrypt.ChallengeType { case "TLS-ALPN-01": // Configuration via autocert with TLS-ALPN-01 (https://tools.ietf.org/html/rfc8737) // The RFC requires that the validation is done on port 443; in other words, headscale @@ -719,7 +719,7 @@ func (h *Headscale) getTLSSettings() (*tls.Config, error) { go func() { log.Fatal(). Caller(). - Err(http.ListenAndServe(h.cfg.TLSLetsEncryptListen, certManager.HTTPHandler(http.HandlerFunc(h.redirect)))). + Err(http.ListenAndServe(h.cfg.TLS.LetsEncrypt.Listen, certManager.HTTPHandler(http.HandlerFunc(h.redirect)))). Msg("failed to set up a HTTP server") }() @@ -728,7 +728,7 @@ func (h *Headscale) getTLSSettings() (*tls.Config, error) { default: return nil, errUnsupportedLetsEncryptChallengeType } - } else if h.cfg.TLSCertPath == "" { + } else if h.cfg.TLS.CertPath == "" { if !strings.HasPrefix(h.cfg.ServerURL, "http://") { log.Warn().Msg("Listening without TLS but ServerURL does not start with http://") } @@ -741,16 +741,16 @@ func (h *Headscale) getTLSSettings() (*tls.Config, error) { log.Info().Msg(fmt.Sprintf( "Client authentication (mTLS) is \"%s\". See the docs to learn about configuring this setting.", - h.cfg.TLSClientAuthMode)) + h.cfg.TLS.ClientAuthMode)) tlsConfig := &tls.Config{ - ClientAuth: h.cfg.TLSClientAuthMode, + ClientAuth: h.cfg.TLS.ClientAuthMode, NextProtos: []string{"http/1.1"}, Certificates: make([]tls.Certificate, 1), MinVersion: tls.VersionTLS12, } - tlsConfig.Certificates[0], err = tls.LoadX509KeyPair(h.cfg.TLSCertPath, h.cfg.TLSKeyPath) + tlsConfig.Certificates[0], err = tls.LoadX509KeyPair(h.cfg.TLS.CertPath, h.cfg.TLS.KeyPath) return tlsConfig, err } diff --git a/config.go b/config.go index 070a90b4..23f0c825 100644 --- a/config.go +++ b/config.go @@ -39,14 +39,7 @@ type Config struct { DBuser string DBpass string - TLSLetsEncryptListen string - TLSLetsEncryptHostname string - TLSLetsEncryptCacheDir string - TLSLetsEncryptChallengeType string - - TLSCertPath string - TLSKeyPath string - TLSClientAuthMode tls.ClientAuthType + TLS TLSConfig ACMEURL string ACMEEmail string @@ -65,6 +58,21 @@ type Config struct { ACL ACLConfig } +type TLSConfig struct { + CertPath string + KeyPath string + ClientAuthMode tls.ClientAuthType + + LetsEncrypt LetsEncryptConfig +} + +type LetsEncryptConfig struct { + Listen string + Hostname string + CacheDir string + ChallengeType string +} + type OIDCConfig struct { Issuer string ClientID string @@ -193,6 +201,30 @@ func LoadConfig(path string) error { } } +func GetTLSConfig() TLSConfig { + tlsClientAuthMode, _ := LookupTLSClientAuthMode( + viper.GetString("tls_client_auth_mode"), + ) + + return TLSConfig{ + LetsEncrypt: LetsEncryptConfig{ + Hostname: viper.GetString("tls_letsencrypt_hostname"), + Listen: viper.GetString("tls_letsencrypt_listen"), + CacheDir: AbsolutePathFromConfigPath( + viper.GetString("tls_letsencrypt_cache_dir"), + ), + ChallengeType: viper.GetString("tls_letsencrypt_challenge_type"), + }, + CertPath: AbsolutePathFromConfigPath( + viper.GetString("tls_cert_path"), + ), + KeyPath: AbsolutePathFromConfigPath( + viper.GetString("tls_key_path"), + ), + ClientAuthMode: tlsClientAuthMode, + } +} + func GetDERPConfig() DERPConfig { serverEnabled := viper.GetBool("derp.server.enabled") serverRegionID := viper.GetInt("derp.server.region_id") @@ -394,10 +426,6 @@ func GetHeadscaleConfig() Config { Msgf("'ip_prefixes' not configured, falling back to default: %v", prefixes) } - tlsClientAuthMode, _ := LookupTLSClientAuthMode( - viper.GetString("tls_client_auth_mode"), - ) - return Config{ ServerURL: viper.GetString("server_url"), Addr: viper.GetString("listen_addr"), @@ -425,20 +453,7 @@ func GetHeadscaleConfig() Config { DBuser: viper.GetString("db_user"), DBpass: viper.GetString("db_pass"), - TLSLetsEncryptHostname: viper.GetString("tls_letsencrypt_hostname"), - TLSLetsEncryptListen: viper.GetString("tls_letsencrypt_listen"), - TLSLetsEncryptCacheDir: AbsolutePathFromConfigPath( - viper.GetString("tls_letsencrypt_cache_dir"), - ), - TLSLetsEncryptChallengeType: viper.GetString("tls_letsencrypt_challenge_type"), - - TLSCertPath: AbsolutePathFromConfigPath( - viper.GetString("tls_cert_path"), - ), - TLSKeyPath: AbsolutePathFromConfigPath( - viper.GetString("tls_key_path"), - ), - TLSClientAuthMode: tlsClientAuthMode, + TLS: GetTLSConfig(), DNSConfig: dnsConfig,