k8s: Obtain relevant information from Rancher 98/88798/4
authorPawel Wieczorek <p.wieczorek2@samsung.com>
Sun, 26 May 2019 13:35:02 +0000 (15:35 +0200)
committerGary Wu <gary.wu@futurewei.com>
Mon, 24 Jun 2019 14:54:30 +0000 (14:54 +0000)
This patch introduces Rancher queries using its CLI client. It depends
on having utility binary located in PATH and providing configuration
file prior first use.

Issue-ID: SECCOM-235
Change-Id: Idb011e27b4801c5700b4482656463849736298da
Signed-off-by: Pawel Wieczorek <p.wieczorek2@samsung.com>
test/security/k8s/src/check/cmd/check/check.go
test/security/k8s/src/check/rancher/rancher.go [new file with mode: 0644]

index 18487e2..e48088a 100644 (file)
@@ -2,8 +2,16 @@ package main
 
 import (
        "flag"
+       "log"
+
+       "check/rancher"
 )
 
 func main() {
        flag.Parse()
+       k8sParams, err := rancher.GetK8sParams()
+       if err != nil {
+               log.Fatal(err)
+       }
+       log.Printf("%s\n", k8sParams)
 }
diff --git a/test/security/k8s/src/check/rancher/rancher.go b/test/security/k8s/src/check/rancher/rancher.go
new file mode 100644 (file)
index 0000000..d60b73b
--- /dev/null
@@ -0,0 +1,87 @@
+// Package rancher wraps Rancher commands necessary for K8s inspection.
+package rancher
+
+import (
+       "bytes"
+       "errors"
+       "os/exec"
+)
+
+const (
+       bin                      = "rancher"
+       paramHost                = "--host"
+       cmdHosts                 = "hosts"
+       cmdHostsParams           = "--quiet"
+       cmdDocker                = "docker"
+       cmdDockerCmdPs           = "ps"
+       cmdDockerCmdPsParams     = "--no-trunc"
+       cmdDockerCmdPsFilter     = "--filter"
+       cmdDockerCmdPsFilterArgs = "label=io.rancher.stack_service.name=kubernetes/kubernetes"
+       cmdDockerCmdPsFormat     = "--format"
+       cmdDockerCmdPsFormatArgs = "{{.Command}}"
+       k8sProcess               = "kube-apiserver"
+)
+
+// GetK8sParams returns parameters of running Kubernetes API server.
+// It queries default environment set in configuration file.
+func GetK8sParams() ([]string, error) {
+       hosts, err := listHosts()
+       if err != nil {
+               return []string{}, err
+       }
+
+       for _, host := range hosts {
+               cmd, err := getK8sCmd(host)
+               if err != nil {
+                       return []string{}, err
+               }
+
+               if len(cmd) > 0 {
+                       i := bytes.Index(cmd, []byte(k8sProcess))
+                       if i == -1 {
+                               return []string{}, errors.New("missing " + k8sProcess + " command")
+                       }
+                       return btos(cmd[i+len(k8sProcess):]), nil
+               }
+       }
+       return []string{}, nil
+}
+
+// listHosts lists IDs of active hosts.
+// It queries default environment set in configuration file.
+func listHosts() ([]string, error) {
+       cmd := exec.Command(bin, cmdHosts, cmdHostsParams)
+       out, err := cmd.Output()
+       if err != nil {
+               return nil, err
+       }
+       return btos(out), nil
+}
+
+// getK8sCmd returns running Kubernetes API server command with its parameters.
+// It queries default environment set in configuration file.
+func getK8sCmd(host string) ([]byte, error) {
+       // Following is equivalent to:
+       // $ rancher --host $HOST \
+       //   docker ps --no-trunc \
+       //   --filter "label=io.rancher.stack_service.name=kubernetes/kubernetes" \
+       //   --format "{{.Command}}"
+       cmd := exec.Command(bin, paramHost, host,
+               cmdDocker, cmdDockerCmdPs, cmdDockerCmdPsParams,
+               cmdDockerCmdPsFilter, cmdDockerCmdPsFilterArgs,
+               cmdDockerCmdPsFormat, cmdDockerCmdPsFormatArgs)
+       out, err := cmd.Output()
+       if err != nil {
+               return nil, err
+       }
+       return out, nil
+}
+
+// btos converts slice of bytes to slice of strings split by white space characters.
+func btos(in []byte) []string {
+       var out []string
+       for _, b := range bytes.Fields(in) {
+               out = append(out, string(b))
+       }
+       return out
+}