From 725fda68dc0cd50c08113d5726eee4047804ddf1 Mon Sep 17 00:00:00 2001 From: Cameron Moore Date: Fri, 27 Dec 2019 11:51:44 -0600 Subject: [PATCH 1/3] Add logfile feature --- docs/Webhook-Parameters.md | 2 ++ webhook.go | 14 +++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/Webhook-Parameters.md b/docs/Webhook-Parameters.md index 7d5beed..6e88a37 100644 --- a/docs/Webhook-Parameters.md +++ b/docs/Webhook-Parameters.md @@ -19,6 +19,8 @@ Usage of webhook: path to the HTTPS certificate private key pem file (default "key.pem") -list-cipher-suites list available TLS cipher suites + -logfile string + send log output to a file; implicitly enables verbose logging -nopanic do not panic if hooks cannot be loaded when webhook is not running in verbose mode -port int diff --git a/webhook.go b/webhook.go index 6807520..2902030 100644 --- a/webhook.go +++ b/webhook.go @@ -33,6 +33,7 @@ var ( ip = flag.String("ip", "0.0.0.0", "ip the webhook should serve hooks on") port = flag.Int("port", 9000, "port the webhook should serve hooks on") verbose = flag.Bool("verbose", false, "show verbose output") + logPath = flag.String("logfile", "", "send log output to a file; implicitly enables verbose logging") debug = flag.Bool("debug", false, "show debug output") noPanic = flag.Bool("nopanic", false, "do not panic if hooks cannot be loaded when webhook is not running in verbose mode") hotReload = flag.Bool("hotreload", false, "watch hooks file for changes and reload them automatically") @@ -103,7 +104,7 @@ func main() { os.Exit(1) } - if *debug { + if *debug || *logPath != "" { *verbose = true } @@ -111,6 +112,17 @@ func main() { hooksFiles = append(hooksFiles, "hooks.json") } + if *logPath != "" { + file, err := os.OpenFile(*logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + if err != nil { + log.Printf("error opening log file %q: %v", *logPath, err) + + return + } + + log.SetOutput(file) + } + log.SetPrefix("[webhook] ") log.SetFlags(log.Ldate | log.Ltime) From 5af6e4d1ec870ec1c688cc8a89c41ebf8f5976a3 Mon Sep 17 00:00:00 2001 From: Cameron Moore Date: Fri, 27 Dec 2019 12:01:12 -0600 Subject: [PATCH 2/3] Open listener port earlier --- webhook.go | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/webhook.go b/webhook.go index 2902030..f87be2c 100644 --- a/webhook.go +++ b/webhook.go @@ -112,6 +112,23 @@ func main() { hooksFiles = append(hooksFiles, "hooks.json") } + addr := fmt.Sprintf("%s:%d", *ip, *port) + + // Open listener early so we can drop privileges. + ln, err := net.Listen("tcp", addr) + if err != nil { + log.Printf("error listening on port: %s", err) + return + } + + if *setUID != 0 { + err := dropPrivileges(*setUID, *setGID) + if err != nil { + log.Printf("error dropping privileges: %s", err) + return + } + } + if *logPath != "" { file, err := os.OpenFile(*logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { @@ -217,29 +234,12 @@ func main() { r.HandleFunc(hooksURL, hookHandler) - addr := fmt.Sprintf("%s:%d", *ip, *port) - // Create common HTTP server settings svr := &http.Server{ Addr: addr, Handler: r, } - // Open listener - ln, err := net.Listen("tcp", addr) - if err != nil { - log.Printf("error listening on port: %s", err) - return - } - - if *setUID != 0 { - err := dropPrivileges(*setUID, *setGID) - if err != nil { - log.Printf("error dropping privileges: %s", err) - return - } - } - // Serve HTTP if !*secure { log.Printf("serving hooks on http://%s%s", addr, hooksURL) From fda328dc23ec3c87fc91bd57ff75cc53e0f9dd58 Mon Sep 17 00:00:00 2001 From: Cameron Moore Date: Sat, 28 Dec 2019 20:50:33 -0600 Subject: [PATCH 3/3] Refactor fatal logging during service startup Create a log queue to postpone the first log write until after privilege dropping and log file opening. --- webhook.go | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/webhook.go b/webhook.go index f87be2c..1a871a9 100644 --- a/webhook.go +++ b/webhook.go @@ -94,13 +94,14 @@ func main() { if *justListCiphers { err := writeTLSSupportedCipherStrings(os.Stdout, getTLSMinVersion(*tlsMinVersion)) if err != nil { - log.Fatal(err) + fmt.Println(err) + os.Exit(1) } os.Exit(0) } if (*setUID != 0 || *setGID != 0) && (*setUID == 0 || *setGID == 0) { - fmt.Println("Error: setuid and setgid options must be used together") + fmt.Println("error: setuid and setgid options must be used together") os.Exit(1) } @@ -112,37 +113,49 @@ func main() { hooksFiles = append(hooksFiles, "hooks.json") } + // logQueue is a queue for log messages encountered during startup. We need + // to queue the messages so that we can handle any privilege dropping and + // log file opening prior to writing our first log message. + var logQueue []string + addr := fmt.Sprintf("%s:%d", *ip, *port) // Open listener early so we can drop privileges. ln, err := net.Listen("tcp", addr) if err != nil { - log.Printf("error listening on port: %s", err) - return + logQueue = append(logQueue, fmt.Sprintf("error listening on port: %s", err)) + // we'll bail out below } if *setUID != 0 { err := dropPrivileges(*setUID, *setGID) if err != nil { - log.Printf("error dropping privileges: %s", err) - return + logQueue = append(logQueue, fmt.Sprintf("error dropping privileges: %s", err)) + // we'll bail out below } } if *logPath != "" { file, err := os.OpenFile(*logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { - log.Printf("error opening log file %q: %v", *logPath, err) - - return + logQueue = append(logQueue, fmt.Sprintf("error opening log file %q: %v", *logPath, err)) + // we'll bail out below + } else { + log.SetOutput(file) } - - log.SetOutput(file) } log.SetPrefix("[webhook] ") log.SetFlags(log.Ldate | log.Ltime) + if len(logQueue) != 0 { + for i := range logQueue { + log.Println(logQueue[i]) + } + + os.Exit(1) + } + if !*verbose { log.SetOutput(ioutil.Discard) }