12 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13 "k8s.io/client-go/kubernetes"
14 "k8s.io/client-go/tools/clientcmd"
16 "github.com/Ullaakut/nmap"
18 "onap.local/sslendpoints/ports"
36 if home := os.Getenv("HOME"); home != "" {
37 kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
39 kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
41 namespace = flag.String("namespace", "", "(optional) name of specific namespace to scan")
42 xfailName = flag.String("xfail", "", "(optional) absolute path to the expected failures file")
45 var listOptions metav1.ListOptions
47 listOptions = metav1.ListOptions{FieldSelector: "metadata.namespace=" + *namespace}
50 var xfails map[uint16]string
52 xfailFile, err := os.Open(*xfailName)
54 log.Printf("Unable to open expected failures file: %v", err)
55 log.Println("All non-SSL NodePorts will be reported")
57 defer xfailFile.Close()
59 r := csv.NewReader(xfailFile)
61 r.Comment = xfailComment
62 r.FieldsPerRecord = xfailFields
64 xfailData, err := r.ReadAll()
66 log.Printf("Unable to read expected failures file: %v", err)
67 log.Println("All non-SSL NodePorts will be reported")
71 xfails, ok = ports.ConvertNodePorts(xfailData)
73 log.Println("No usable data in expected failures file")
74 log.Println("All non-SSL NodePorts will be reported")
78 // use the current context in kubeconfig
79 config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
81 log.Panicf("Unable to build cluster config: %v", err)
84 // create the clientset
85 clientset, err := kubernetes.NewForConfig(config)
87 log.Panicf("Unable to build client: %v", err)
90 // get list of nodes to extract addresses for running scan
91 nodes, err := clientset.CoreV1().Nodes().List(metav1.ListOptions{})
93 log.Panicf("Unable to get list of nodes: %v", err)
96 // filter out addresses for running scan
97 addresses, ok := ports.FilterIPAddresses(nodes)
99 log.Println("There are no IP addresses to run scan")
103 // get list of services to extract nodeport information
104 services, err := clientset.CoreV1().Services("").List(listOptions)
106 log.Panicf("Unable to get list of services: %v", err)
109 // filter out nodeports with corresponding services from service list
110 nodeports, ok := ports.FilterNodePorts(services)
112 log.Println("There are no NodePorts in the cluster")
116 // filter out expected failures here before running the scan
117 ports.FilterXFailNodePorts(xfails, nodeports)
119 // extract ports for running the scan
121 for port := range nodeports {
122 ports = append(ports, strconv.Itoa(int(port)))
125 // run nmap on the first address found for given cluster [1] filtering out SSL-tunelled ports
126 // [1] https://kubernetes.io/docs/concepts/services-networking/service/#nodeport
127 // "Each node proxies that port (the same port number on every Node) into your Service."
128 scanner, err := nmap.NewScanner(
129 nmap.WithTargets(addresses[0]),
130 nmap.WithPorts(ports...),
131 nmap.WithServiceInfo(),
132 nmap.WithTimingTemplate(nmap.TimingAggressive),
133 nmap.WithFilterPort(func(p nmap.Port) bool {
134 if p.Service.Tunnel == "ssl" {
137 if strings.HasPrefix(p.State.State, "closed") {
140 if strings.HasPrefix(p.State.State, "filtered") {
147 log.Panicf("Unable to create nmap scanner: %v", err)
150 result, _, err := scanner.Run()
152 log.Panicf("Scan failed: %v", err)
155 // scan was run on a single host
156 if len(result.Hosts) < 1 {
157 log.Panicln("No host information in scan results")
160 // host address in the results might be ipv4 or mac
161 for _, address := range result.Hosts[0].Addresses {
162 if address.AddrType == ipv4AddrType {
163 log.Printf("Host %s\n", address)
166 log.Printf("PORT\tSERVICE")
167 for _, port := range result.Hosts[0].Ports {
168 log.Printf("%d\t%s\n", port.ID, nodeports[port.ID])
171 // report non-SSL services and their number
172 log.Printf("There are %d non-SSL NodePorts in the cluster\n", len(result.Hosts[0].Ports))
173 os.Exit(len(result.Hosts[0].Ports))