diff --git a/README.md b/README.md index 792959a..2201e5d 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ WIP listen_port: 8080 tls_cert_file: server.crt tls_key_file: server.key +tls_ignore_cert: true server_timeout_read: 5 # Default 600 server_timeout_write: 10 # Default 600 # hooks @@ -38,7 +39,6 @@ hide_repowarn: true passthroughauth: true # connectivity check_interval: 5 -ignore_cert: true username: svc_pveportal password: insecure # clusters diff --git a/pkg/config/main.go b/pkg/config/main.go index b150ab0..4c44c5b 100644 --- a/pkg/config/main.go +++ b/pkg/config/main.go @@ -48,7 +48,6 @@ func parseConfig(yaml *YamlConfig) (*Config, error) { Name: hv.Name, Endpoint: ep, Online: false, - IgnoreCert: defaultbool(lastbool(yaml.IgnoreCert, cv.IgnoreCert, hv.IgnoreCert), false), HideRepowarn: defaultbool(lastbool(yaml.HideRepowarn, cv.HideRepowarn, hv.HideRepowarn), false), Username: user, Password: pass, @@ -75,6 +74,7 @@ func parseConfig(yaml *YamlConfig) (*Config, error) { SessionTime: sessionTime, TLSCertFile: yaml.TLSCertFile, TLSKeyFile: yaml.TLSKeyFile, + TLSIgnoreCert: defaultbool(yaml.TLSIgnoreCert, false), ServerTimeoutWrite: defaultint(yaml.ServerTimeoutWrite, 600), ServerTimeoutRead: defaultint(yaml.ServerTimeoutRead, 600), }, nil diff --git a/pkg/config/schema.go b/pkg/config/schema.go index 80f303e..402e8cb 100644 --- a/pkg/config/schema.go +++ b/pkg/config/schema.go @@ -11,13 +11,13 @@ type YamlConfig struct { ListenPort uint16 `yaml:"listen_port"` TLSCertFile string `yaml:"tls_cert_file"` TLSKeyFile string `yaml:"tls_key_file"` + TLSIgnoreCert *bool `yaml:"tls_ignore_cert"` ServerTimeoutWrite *int `yaml:"server_timeout_write"` ServerTimeoutRead *int `yaml:"server_timeout_read"` Clusters []YamlCluster `yaml:"clusters"` PassthroughAuth *bool `yaml:"passthroughauth"` SessionTime string `yaml:"sessiontime"` // inheritable - IgnoreCert *bool `yaml:"ignore_cert"` HideRepowarn *bool `yaml:"hide_repowarn"` Username string `yaml:"username"` Password string `yaml:"password"` @@ -28,7 +28,6 @@ type YamlCluster struct { Name string `yaml:"name"` Hosts []YamlHost `yaml:"hosts"` // inheritable - IgnoreCert *bool `yaml:"ignore_cert"` HideRepowarn *bool `yaml:"hide_repowarn"` Username string `yaml:"username"` Password string `yaml:"password"` @@ -39,7 +38,6 @@ type YamlHost struct { Name string `yaml:"name"` Endpoint string `yaml:"endpoint"` // inheritable - IgnoreCert *bool `yaml:"ignore_cert"` HideRepowarn *bool `yaml:"hide_repowarn"` Username string `yaml:"username"` Password string `yaml:"password"` @@ -52,6 +50,7 @@ type Config struct { SessionTime time.Duration TLSCertFile string TLSKeyFile string + TLSIgnoreCert bool Clusters []Cluster ServerTimeoutWrite int ServerTimeoutRead int diff --git a/pkg/proxy/handler.go b/pkg/proxy/handler.go index cdfa738..945dd86 100644 --- a/pkg/proxy/handler.go +++ b/pkg/proxy/handler.go @@ -72,14 +72,6 @@ func (p *Proxy) proxyHandler() func(w http.ResponseWriter, r *http.Request) { } func (p *Proxy) proxyRequest(cluster string, host *config.Host, w http.ResponseWriter, r *http.Request) error { - client := &http.Client{ - Transport: &http.Transport{ - Proxy: http.ProxyFromEnvironment, - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: host.IgnoreCert, //nolint:gosec,G402 - }, - }, - } tgturl := *r.URL tgturl.Scheme = host.Endpoint.Scheme tgturl.Host = host.Endpoint.Host @@ -103,7 +95,7 @@ func (p *Proxy) proxyRequest(cluster string, host *config.Host, w http.ResponseW return err } } - resp, err := client.Do(req) + resp, err := p.httpClient.Do(req) if err != nil { return err } diff --git a/pkg/proxy/main.go b/pkg/proxy/main.go index 6d243d3..95ad4ff 100644 --- a/pkg/proxy/main.go +++ b/pkg/proxy/main.go @@ -45,17 +45,20 @@ func Run(www embed.FS) error { if err != nil { return err } - fs := http.FileServer(http.FS(htmlContent)) - http.HandleFunc(fmt.Sprintf("%sapi/clusters", localHTTPDir), listClusters(cfg.Clusters)) - http.HandleFunc(fmt.Sprintf("%sapi/switchcluster", localHTTPDir), switchCluster()) - http.Handle(localHTTPDir, http.StripPrefix(localHTTPDir, fs)) - prx := NewProxy(cfg) - handler := prx.proxyHandler() - http.HandleFunc("/", handler) + prx, err := NewProxy(cfg) + if err != nil { + return err + } + defer prx.close() tlscfg, err := prx.parseTLSConfig() if err != nil { return err } + fs := http.FileServer(http.FS(htmlContent)) + http.HandleFunc(fmt.Sprintf("%sapi/clusters", localHTTPDir), listClusters(cfg.Clusters)) + http.HandleFunc(fmt.Sprintf("%sapi/switchcluster", localHTTPDir), switchCluster()) + http.Handle(localHTTPDir, http.StripPrefix(localHTTPDir, fs)) + http.HandleFunc("/", prx.proxyHandler()) srv := &http.Server{ ReadTimeout: time.Duration(cfg.ServerTimeoutRead) * time.Second, WriteTimeout: time.Duration(cfg.ServerTimeoutWrite) * time.Second, @@ -122,6 +125,7 @@ func (p *Proxy) parseTLSConfig() (*tls.Config, error) { return &tls.Config{ Certificates: []tls.Certificate{crt}, MinVersion: tls.VersionTLS12, + KeyLogWriter: p.sslKeyLogFile, }, nil } diff --git a/pkg/proxy/sessions.go b/pkg/proxy/sessions.go index c75c9ee..8038b4d 100644 --- a/pkg/proxy/sessions.go +++ b/pkg/proxy/sessions.go @@ -9,6 +9,7 @@ import ( "fmt" "io" "net/http" + "os" "sync" "time" @@ -18,16 +19,48 @@ import ( ) type Proxy struct { - config *config.Config - sessions map[uuid.UUID]map[string]http.Cookie - sessionsLock *sync.RWMutex + config *config.Config + sessions map[uuid.UUID]map[string]http.Cookie + sessionsLock *sync.RWMutex + httpClient *http.Client + sslKeyLogFile io.WriteCloser } -func NewProxy(config *config.Config) *Proxy { - return &Proxy{ +func NewProxy(config *config.Config) (*Proxy, error) { + transport := &http.Transport{ + Proxy: http.ProxyFromEnvironment, + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: config.TLSIgnoreCert, //nolint:gosec,G402 + }, + ForceAttemptHTTP2: true, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + } + p := &Proxy{ sessions: make(map[uuid.UUID]map[string]http.Cookie), sessionsLock: &sync.RWMutex{}, config: config, + httpClient: &http.Client{ + Transport: transport, + }, + } + path := os.Getenv("SSLKEYLOGFILE") + if len(path) != 0 { + var err error + p.sslKeyLogFile, err = os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o600) + if err != nil { + return nil, fmt.Errorf("could not open SSLKEYLOGFILE: %w", err) + } + transport.TLSClientConfig.KeyLogWriter = p.sslKeyLogFile + } + return p, nil +} + +func (p *Proxy) close() { + if p.sslKeyLogFile != nil { + p.sslKeyLogFile.Close() } } @@ -66,14 +99,6 @@ func (p *Proxy) multiAuth(log logrus.FieldLogger, w http.ResponseWriter, r *http resps := make(map[string]http.Response) for _, v := range p.config.Clusters { host := getHealthyHost(v.Hosts) - client := &http.Client{ - Transport: &http.Transport{ - Proxy: http.ProxyFromEnvironment, - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: host.IgnoreCert, //nolint:gosec,G402 - }, - }, - } tgturl := *r.URL tgturl.Scheme = host.Endpoint.Scheme tgturl.Host = host.Endpoint.Host @@ -87,7 +112,7 @@ func (p *Proxy) multiAuth(log logrus.FieldLogger, w http.ResponseWriter, r *http continue } p.copyHeaders(r.Header, req.Header) - resp, err := client.Do(req) + resp, err := p.httpClient.Do(req) if err != nil { log.WithError(err).Error("failed multiauth") continue diff --git a/res/pveportal.yaml b/res/pveportal.yaml index aeec100..0962fa6 100644 --- a/res/pveportal.yaml +++ b/res/pveportal.yaml @@ -2,6 +2,7 @@ listen_port: 80 # tls_cert_file: server.crt # tls_key_file: server.key +tls_ignore_cert: true # hooks hide_repowarn: true @@ -9,7 +10,6 @@ passthroughauth: true # connectivity check_interval: 5 -ignore_cert: true username: dummy password: dummy