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"
35 if home := os.Getenv("HOME"); home != "" {
36 kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
38 kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
40 xfailName = flag.String("xfail", "", "(optional) absolute path to the expected failures file")
43 xfails := make(map[uint16]string)
45 xfailFile, err := os.Open(*xfailName)
47 log.Printf("Unable to open expected failures file: %v", err)
48 log.Println("All non-SSL NodePorts will be reported")
50 defer xfailFile.Close()
52 r := csv.NewReader(xfailFile)
54 r.Comment = xfailComment
55 r.FieldsPerRecord = xfailFields
57 xfailData, err := r.ReadAll()
59 log.Printf("Unable to read expected failures file: %v", err)
60 log.Println("All non-SSL NodePorts will be reported")
64 xfails, ok = ports.ConvertNodePorts(xfailData)
66 log.Println("No usable data in expected failures file")
67 log.Println("All non-SSL NodePorts will be reported")
71 // use the current context in kubeconfig
72 config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
74 log.Panicf("Unable to build cluster config: %v", err)
77 // create the clientset
78 clientset, err := kubernetes.NewForConfig(config)
80 log.Panicf("Unable to build client: %v", err)
83 // get list of nodes to extract addresses for running scan
84 nodes, err := clientset.CoreV1().Nodes().List(metav1.ListOptions{})
86 log.Panicf("Unable to get list of nodes: %v", err)
89 // filter out addresses for running scan
90 addresses, ok := ports.FilterIPAddresses(nodes)
92 log.Println("There are no IP addresses to run scan")
96 // get list of services to extract nodeport information
97 services, err := clientset.CoreV1().Services("").List(metav1.ListOptions{})
99 log.Panicf("Unable to get list of services: %v", err)
102 // filter out nodeports with corresponding services from service list
103 nodeports, ok := ports.FilterNodePorts(services)
105 log.Println("There are no NodePorts in the cluster")
109 // filter out expected failures here before running the scan
110 ports.FilterXFailNodePorts(xfails, nodeports)
112 // extract ports for running the scan
114 for port := range nodeports {
115 ports = append(ports, strconv.Itoa(int(port)))
118 // run nmap on the first address found for given cluster [1] filtering out SSL-tunelled ports
119 // [1] https://kubernetes.io/docs/concepts/services-networking/service/#nodeport
120 // "Each node proxies that port (the same port number on every Node) into your Service."
121 scanner, err := nmap.NewScanner(
122 nmap.WithTargets(addresses[0]),
123 nmap.WithPorts(ports...),
124 nmap.WithServiceInfo(),
125 nmap.WithTimingTemplate(nmap.TimingAggressive),
126 nmap.WithFilterPort(func(p nmap.Port) bool {
127 if p.Service.Tunnel == "ssl" {
130 if strings.HasPrefix(p.State.State, "closed") {
133 if strings.HasPrefix(p.State.State, "filtered") {
140 log.Panicf("Unable to create nmap scanner: %v", err)
143 result, _, err := scanner.Run()
145 log.Panicf("Scan failed: %v", err)
148 // scan was run on a single host
149 if len(result.Hosts) < 1 {
150 log.Panicln("No host information in scan results")
153 // host address in the results might be ipv4 or mac
154 for _, address := range result.Hosts[0].Addresses {
155 if address.AddrType == ipv4AddrType {
156 log.Printf("Host %s\n", address)
159 log.Printf("PORT\tSERVICE")
160 for _, port := range result.Hosts[0].Ports {
161 log.Printf("%d\t%s\n", port.ID, nodeports[port.ID])
164 // report non-SSL services and their number
165 log.Printf("There are %d non-SSL NodePorts in the cluster\n", len(result.Hosts[0].Ports))
166 os.Exit(len(result.Hosts[0].Ports))