Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(config/server): Add option to deploy a HTTP server for the metrics endpoint #565

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
14 changes: 13 additions & 1 deletion config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)},
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -482,6 +484,8 @@ func getConfig() *types.Configuration {
}
}

v.GetStringSlice("TLSServer.NoTLSPaths")

v.GetStringMapString("Customfields")
v.GetStringMapString("Templatedfields")
v.GetStringMapString("Webhook.CustomHeaders")
Expand All @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down
4 changes: 4 additions & 0 deletions config_example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
83 changes: 73 additions & 10 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand All @@ -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()
}
2 changes: 2 additions & 0 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ type TLSServer struct {
KeyFile string
MutualTLS bool
CaCertFile string
NoTLSPort int
NoTLSPaths []string
}

// SlackOutputConfig represents parameters for Slack
Expand Down
Loading