diff --git a/README.md b/README.md index aaaf171d3..27f287c35 100644 --- a/README.md +++ b/README.md @@ -208,6 +208,11 @@ tlsserver: keyfile: "/etc/certs/server/server.key" # server key mutualtls: false # if true, mTLS server will be deployed instead of TLS, deploy also has to be true cacertfile: "/etc/certs/server/ca.crt" # for client certification if mutualtls is true + notlsport: 2810 # port to serve http server serving selected endpoints (default: 2810) + # notlspaths: # if not empty, a separate http server will be deployed for the specified endpoints + # - "/metrics" + # - "/healthz" + slack: webhookurl: "" # Slack WebhookURL (ex: https://hooks.slack.com/services/XXXX/YYYY/ZZZZ), if not empty, Slack output is enabled @@ -688,6 +693,8 @@ care of lower/uppercases**) : `yaml: a.b --> envvar: A_B` : - **TLSSERVER_KEYFILE**: server key file for TLS Server (default: "/etc/certs/server/server.key") - **TLSSERVER_MUTUALTLS**: if _true_ mutual TLS server will be deployed instead of TLS, deploy also has to be true - **TLSSERVER_CACERTFILE**: CA certification file for client certification if TLSSERVER_MUTUALTLS is _true_ (default: "/etc/certs/server/ca.crt") +- **TLSSERVER_NOTLSPORT**: port to serve http server serving selected endpoints (default: 2810) +- **TLSSERVER_NOTLSPATHS**: a comma separated list of endpoints, if not empty, a separate http server will be deployed for the specified endpoints (e.g.: "/metrics,/healtz") - **SLACK_WEBHOOKURL** : Slack Webhook URL (ex: https://hooks.slack.com/services/XXXX/YYYY/ZZZZ) - **SLACK_CHANNEL** : Slack Channel (optionnal) - **SLACK_FOOTER** : Slack footer diff --git a/config.go b/config.go index de47185ea..9028fe66c 100644 --- a/config.go +++ b/config.go @@ -23,6 +23,7 @@ func getConfig() *types.Configuration { c := &types.Configuration{ Customfields: make(map[string]string), Templatedfields: make(map[string]string), + TLSServer: types.TLSServer{NoTLSPaths: make([]string, 0)}, Grafana: types.GrafanaOutputConfig{CustomHeaders: make(map[string]string)}, Loki: types.LokiOutputConfig{CustomHeaders: make(map[string]string)}, Elasticsearch: types.ElasticsearchOutputConfig{CustomHeaders: make(map[string]string)}, @@ -58,6 +59,7 @@ func getConfig() *types.Configuration { v.SetDefault("TLSServer.KeyFile", "/etc/certs/server/server.key") v.SetDefault("TLSServer.MutualTLS", false) v.SetDefault("TLSServer.CaCertFile", "/etc/certs/server/ca.crt") + v.SetDefault("TLSServer.NoTLSPort", 2810) v.SetDefault("Slack.WebhookURL", "") v.SetDefault("Slack.Footer", "https://github.com/falcosecurity/falcosidekick") @@ -482,6 +484,8 @@ func getConfig() *types.Configuration { } } + v.GetStringSlice("TLSServer.NoTLSPaths") + v.GetStringMapString("Customfields") v.GetStringMapString("Templatedfields") v.GetStringMapString("Webhook.CustomHeaders") @@ -494,6 +498,10 @@ func getConfig() *types.Configuration { log.Printf("[ERROR] : Error unmarshalling config : %s", err) } + if value, present := os.LookupEnv("TLSSERVER_NOTLSPATHS"); present { + c.TLSServer.NoTLSPaths = strings.Split(value, ",") + } + if value, present := os.LookupEnv("CUSTOMFIELDS"); present { customfields := strings.Split(value, ",") for _, label := range customfields { @@ -614,7 +622,11 @@ func getConfig() *types.Configuration { } if c.ListenPort == 0 || c.ListenPort > 65536 { - log.Fatalf("[ERROR] : Bad port number\n") + log.Fatalf("[ERROR] : Bad listening port number\n") + } + + if c.TLSServer.NoTLSPort == 0 || c.TLSServer.NoTLSPort > 65536 { + log.Fatalf("[ERROR] : Bad noTLS server port number\n") } if ip := net.ParseIP(c.ListenAddress); c.ListenAddress != "" && ip == nil { diff --git a/config_example.yaml b/config_example.yaml index ed4e3bfa5..587d9dd50 100644 --- a/config_example.yaml +++ b/config_example.yaml @@ -19,6 +19,10 @@ tlsserver: keyfile: "/etc/certs/server/server.key" # server key mutualtls: false # if true, mTLS server will be deployed instead of TLS, deploy also has to be true cacertfile: "/etc/certs/server/ca.crt" # for client certification if mutualtls is true + notlsport: 2810 # port to serve http server serving selected endpoints (default: 2810) + # notlspaths: # if not empty, a separate http server will be deployed for the specified endpoints + # - "/metrics" + # - "/healthz" slack: diff --git a/main.go b/main.go index ccb4b937a..53ccd7a57 100644 --- a/main.go +++ b/main.go @@ -723,19 +723,46 @@ func init() { } func main() { - http.HandleFunc("/", mainHandler) - http.HandleFunc("/ping", pingHandler) - http.HandleFunc("/healthz", healthHandler) - http.HandleFunc("/test", testHandler) - http.Handle("/metrics", promhttp.Handler()) - - log.Printf("[INFO] : Falco Sidekick is up and listening on %s:%d", config.ListenAddress, config.ListenPort) if config.Debug { log.Printf("[INFO] : Debug mode : %v", config.Debug) } + routes := map[string]http.Handler{ + "/": http.HandlerFunc(mainHandler), + "/ping": http.HandlerFunc(pingHandler), + "/healthz": http.HandlerFunc(healthHandler), + "/test": http.HandlerFunc(testHandler), + "/metrics": promhttp.Handler(), + } + + mainServeMux := http.NewServeMux() + var HTTPServeMux *http.ServeMux + + // configure HTTP routes requested by NoTLSPath config + if config.TLSServer.Deploy { + HTTPServeMux = http.NewServeMux() + for _, r := range config.TLSServer.NoTLSPaths { + handler, ok := routes[r] + if ok { + delete(routes, r) + if config.Debug { + log.Printf("[DEBUG] : %s is served on http", r) + } + HTTPServeMux.Handle(r, handler) + } else { + log.Printf("[WARN] : tlsserver.notlspaths has unknown path '%s'", r) + } + } + } + + // configure main server routes + for r, handler := range routes { + mainServeMux.Handle(r, handler) + } + server := &http.Server{ - Addr: fmt.Sprintf("%s:%d", config.ListenAddress, config.ListenPort), + Addr: fmt.Sprintf("%s:%d", config.ListenAddress, config.ListenPort), + Handler: mainServeMux, // Timeouts ReadTimeout: 60 * time.Second, ReadHeaderTimeout: 60 * time.Second, @@ -767,8 +794,31 @@ func main() { log.Printf("[DEBUG] : running TLS server") } - if err := server.ListenAndServeTLS(config.TLSServer.CertFile, config.TLSServer.KeyFile); err != nil { - log.Fatalf("[ERROR] : %v", err.Error()) + if len(config.TLSServer.NoTLSPaths) != 0 { + if config.Debug { + log.Printf("[DEBUG] : running HTTP server for endpoints defined in tlsserver.notlspaths") + } + + httpServer := &http.Server{ + Addr: fmt.Sprintf("%s:%d", config.ListenAddress, config.TLSServer.NoTLSPort), + Handler: HTTPServeMux, + // Timeouts + ReadTimeout: 60 * time.Second, + ReadHeaderTimeout: 60 * time.Second, + WriteTimeout: 60 * time.Second, + IdleTimeout: 60 * time.Second, + } + log.Printf("[INFO] : Falco Sidekick is up and listening on %s:%d and %s:%d", config.ListenAddress, config.ListenPort, config.ListenAddress, config.TLSServer.NoTLSPort) + + errs := make(chan error, 1) + go serveTLS(server, errs) + go serveHTTP(httpServer, errs) + log.Fatal(<-errs) + } else { + log.Printf("[INFO] : Falco Sidekick is up and listening on %s:%d", config.ListenAddress, config.ListenPort) + if err := server.ListenAndServeTLS(config.TLSServer.CertFile, config.TLSServer.KeyFile); err != nil { + log.Fatalf("[ERROR] : %v", err.Error()) + } } } else { if config.Debug { @@ -779,8 +829,21 @@ func main() { log.Printf("[WARN] : tlsserver.deploy is false but tlsserver.mutualtls is true, change tlsserver.deploy to true to use mTLS") } + if len(config.TLSServer.NoTLSPaths) != 0 { + log.Printf("[WARN] : tlsserver.deploy is false but tlsserver.notlspaths is not empty, change tlsserver.deploy to true to deploy two servers") + } + + log.Printf("[INFO] : Falco Sidekick is up and listening on %s:%d", config.ListenAddress, config.ListenPort) if err := server.ListenAndServe(); err != nil { log.Fatalf("[ERROR] : %v", err.Error()) } } } + +func serveTLS(server *http.Server, errs chan<- error) { + errs <- server.ListenAndServeTLS(config.TLSServer.CertFile, config.TLSServer.KeyFile) +} + +func serveHTTP(server *http.Server, errs chan<- error) { + errs <- server.ListenAndServe() +} diff --git a/types/types.go b/types/types.go index 08011668a..7fa84a73e 100644 --- a/types/types.go +++ b/types/types.go @@ -121,6 +121,8 @@ type TLSServer struct { KeyFile string MutualTLS bool CaCertFile string + NoTLSPort int + NoTLSPaths []string } // SlackOutputConfig represents parameters for Slack