From 5f8a239b30e8a09d91ac777633bf316a3b7e72a1 Mon Sep 17 00:00:00 2001 From: Alex Kursell Date: Wed, 20 Feb 2019 15:17:46 -0500 Subject: [PATCH] Improve cert command --- cmd/dbg/main.go | 84 ++++++++++++++++++++++++++++++++++++------ internal/nginx/main.go | 31 ++++++++++++++-- 2 files changed, 101 insertions(+), 14 deletions(-) diff --git a/cmd/dbg/main.go b/cmd/dbg/main.go index ceabcd51529a..37f646babd05 100644 --- a/cmd/dbg/main.go +++ b/cmd/dbg/main.go @@ -23,6 +23,7 @@ import ( "github.com/spf13/cobra" "k8s.io/ingress-nginx/internal/nginx" "os" + "regexp" ) const ( @@ -80,10 +81,27 @@ func main() { Use: "get [hostname]", Short: "Get the dynamically-loaded certificate information for the given hostname", Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - certGet(args[0]) + RunE: func(cmd *cobra.Command, args []string) error { + staticOnly, err := cmd.Flags().GetBool("static-only") + if err != nil { + return err + } + + dynamicOnly, err := cmd.Flags().GetBool("dynamic-only") + if err != nil { + return err + } + + if staticOnly && dynamicOnly { + return fmt.Errorf("--static-only and --dynamic-only cannot both be specified") + } + + certGet(args[0], staticOnly, dynamicOnly) + return nil }, } + certGetCmd.Flags().Bool("static-only", false, "Only look for an SSL cert loaded from a file inside the container") + certGetCmd.Flags().Bool("dynamic-only", false, "Only look for an SSL cert dynamically loaded by lua") certCmd.AddCommand(certGetCmd) rootCmd.AddCommand(certCmd) @@ -189,19 +207,63 @@ func backendsGet(name string) { fmt.Println("A backend of this name was not found.") } -func certGet(host string) { - statusCode, body, requestErr := nginx.NewGetStatusRequest(certsPath + "?hostname=" + host) - if requestErr != nil { - fmt.Println(requestErr) - return +func certGet(host string, staticOnly bool, dynamicOnly bool) { + if !staticOnly { + statusCode, body, requestErr := nginx.NewGetStatusRequest(certsPath + "?hostname=" + host) + if requestErr != nil { + fmt.Println(requestErr) + return + } + + if statusCode == 200 { + fmt.Println(string(body)) + return + } else if statusCode != 404 { + fmt.Printf("Nginx returned code %v\n", statusCode) + fmt.Println(string(body)) + return + } } - if statusCode != 200 { - fmt.Printf("Nginx returned code %v\n", statusCode) - fmt.Println(string(body)) + + if !dynamicOnly { + conf, err := nginx.ReadNginxConf() + if err != nil { + fmt.Println(err) + return + } + + serverBlock, err := nginx.GetServerBlock(conf, host) + if err != nil { + fmt.Println(err) + return + } + + certPath, err := getCertPath(serverBlock) + if err != nil { + fmt.Printf("No certificate found for host %v\n", host) + return + } + + contents, err := nginx.ReadFileToString(certPath) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println(contents) return } - fmt.Println(string(body)) + fmt.Printf("No cert found for host %v\n", host) +} + +func getCertPath(conf string) (string, error) { + keyRegexp := regexp.MustCompile(`ssl_certificate\s+(.*);`) + match := keyRegexp.FindStringSubmatch(conf) + if match == nil || len(match) < 2 || len(match[1]) == 0 { + return "", fmt.Errorf("No cert found") + } + return match[1], nil } func general() { diff --git a/internal/nginx/main.go b/internal/nginx/main.go index 5d90e87a55a7..88db135c0fc0 100644 --- a/internal/nginx/main.go +++ b/internal/nginx/main.go @@ -18,6 +18,7 @@ package nginx import ( "bytes" + "strings" "encoding/json" "fmt" "io/ioutil" @@ -88,15 +89,39 @@ func NewPostStatusRequest(path, contentType string, data interface{}) (int, []by return res.StatusCode, body, nil } +// GetServerBlock takes an nginx.conf file and a host and tries to find the server block for that host +func GetServerBlock(conf string, host string) (string, error){ + startMsg := fmt.Sprintf("## start server %v", host) + endMsg := fmt.Sprintf("## end server %v", host) + + blockStart := strings.Index(conf, startMsg) + if blockStart < 0 { + return "", fmt.Errorf("Host %v was not found in the controller's nginx.conf", host) + } + blockStart = blockStart + len(startMsg) + + blockEnd := strings.Index(conf, endMsg) + if blockEnd < 0 { + return "", fmt.Errorf("The end of the host server block could not be found, but the beginning was") + } + + return conf[blockStart:blockEnd], nil +} + // ReadNginxConf reads the nginx configuration file into a string func ReadNginxConf() (string, error) { - confFile, err := os.Open("/etc/nginx/nginx.conf") + return ReadFileToString("/etc/nginx/nginx.conf") +} + +// ReadFileToString reads any file into a string +func ReadFileToString(path string) (string, error) { + f, err := os.Open(path) if err != nil { return "", err } - defer confFile.Close() + defer f.Close() - contents, err := ioutil.ReadAll(confFile) + contents, err := ioutil.ReadAll(f) if err != nil { return "", err }