Unify variable initialization
[integration.git] / test / security / sslendpoints / main.go
1 package main
2
3 import (
4         "encoding/csv"
5         "flag"
6         "log"
7         "os"
8         "path/filepath"
9         "strconv"
10         "strings"
11
12         metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13         "k8s.io/client-go/kubernetes"
14         "k8s.io/client-go/tools/clientcmd"
15
16         "github.com/Ullaakut/nmap"
17
18         "onap.local/sslendpoints/ports"
19 )
20
21 const (
22         ipv4AddrType = "ipv4"
23
24         xfailComma   = ' '
25         xfailComment = '#'
26         xfailFields  = 2
27 )
28
29 var (
30         kubeconfig *string
31         namespace  *string
32         xfailName  *string
33 )
34
35 func main() {
36         if home := os.Getenv("HOME"); home != "" {
37                 kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
38         } else {
39                 kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
40         }
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")
43         flag.Parse()
44
45         var listOptions metav1.ListOptions
46         if *namespace != "" {
47                 listOptions = metav1.ListOptions{FieldSelector: "metadata.namespace=" + *namespace}
48         }
49
50         var xfails map[uint16]string
51         if *xfailName != "" {
52                 xfailFile, err := os.Open(*xfailName)
53                 if err != nil {
54                         log.Printf("Unable to open expected failures file: %v", err)
55                         log.Println("All non-SSL NodePorts will be reported")
56                 }
57                 defer xfailFile.Close()
58
59                 r := csv.NewReader(xfailFile)
60                 r.Comma = xfailComma
61                 r.Comment = xfailComment
62                 r.FieldsPerRecord = xfailFields
63
64                 xfailData, err := r.ReadAll()
65                 if err != nil {
66                         log.Printf("Unable to read expected failures file: %v", err)
67                         log.Println("All non-SSL NodePorts will be reported")
68                 }
69
70                 var ok bool
71                 xfails, ok = ports.ConvertNodePorts(xfailData)
72                 if !ok {
73                         log.Println("No usable data in expected failures file")
74                         log.Println("All non-SSL NodePorts will be reported")
75                 }
76         }
77
78         // use the current context in kubeconfig
79         config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
80         if err != nil {
81                 log.Panicf("Unable to build cluster config: %v", err)
82         }
83
84         // create the clientset
85         clientset, err := kubernetes.NewForConfig(config)
86         if err != nil {
87                 log.Panicf("Unable to build client: %v", err)
88         }
89
90         // get list of nodes to extract addresses for running scan
91         nodes, err := clientset.CoreV1().Nodes().List(metav1.ListOptions{})
92         if err != nil {
93                 log.Panicf("Unable to get list of nodes: %v", err)
94         }
95
96         // filter out addresses for running scan
97         addresses, ok := ports.FilterIPAddresses(nodes)
98         if !ok {
99                 log.Println("There are no IP addresses to run scan")
100                 os.Exit(0)
101         }
102
103         // get list of services to extract nodeport information
104         services, err := clientset.CoreV1().Services("").List(listOptions)
105         if err != nil {
106                 log.Panicf("Unable to get list of services: %v", err)
107         }
108
109         // filter out nodeports with corresponding services from service list
110         nodeports, ok := ports.FilterNodePorts(services)
111         if !ok {
112                 log.Println("There are no NodePorts in the cluster")
113                 os.Exit(0)
114         }
115
116         // filter out expected failures here before running the scan
117         ports.FilterXFailNodePorts(xfails, nodeports)
118
119         // extract ports for running the scan
120         var ports []string
121         for port := range nodeports {
122                 ports = append(ports, strconv.Itoa(int(port)))
123         }
124
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" {
135                                 return false
136                         }
137                         if strings.HasPrefix(p.State.State, "closed") {
138                                 return false
139                         }
140                         if strings.HasPrefix(p.State.State, "filtered") {
141                                 return false
142                         }
143                         return true
144                 }),
145         )
146         if err != nil {
147                 log.Panicf("Unable to create nmap scanner: %v", err)
148         }
149
150         result, _, err := scanner.Run()
151         if err != nil {
152                 log.Panicf("Scan failed: %v", err)
153         }
154
155         // scan was run on a single host
156         if len(result.Hosts) < 1 {
157                 log.Panicln("No host information in scan results")
158         }
159
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)
164                 }
165         }
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])
169         }
170
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))
174 }