331979e38d1ef9acd9200d1a66096c13c1c70df2
[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         xfailName  *string
32 )
33
34 func main() {
35         if home := os.Getenv("HOME"); home != "" {
36                 kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
37         } else {
38                 kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
39         }
40         xfailName = flag.String("xfail", "", "(optional) absolute path to the expected failures file")
41         flag.Parse()
42
43         xfails := make(map[uint16]string)
44         if *xfailName != "" {
45                 xfailFile, err := os.Open(*xfailName)
46                 if err != nil {
47                         log.Printf("Unable to open expected failures file: %v", err)
48                         log.Println("All non-SSL NodePorts will be reported")
49                 }
50                 defer xfailFile.Close()
51
52                 r := csv.NewReader(xfailFile)
53                 r.Comma = xfailComma
54                 r.Comment = xfailComment
55                 r.FieldsPerRecord = xfailFields
56
57                 xfailData, err := r.ReadAll()
58                 if err != nil {
59                         log.Printf("Unable to read expected failures file: %v", err)
60                         log.Println("All non-SSL NodePorts will be reported")
61                 }
62
63                 var ok bool
64                 xfails, ok = ports.ConvertNodePorts(xfailData)
65                 if !ok {
66                         log.Println("No usable data in expected failures file")
67                         log.Println("All non-SSL NodePorts will be reported")
68                 }
69         }
70
71         // use the current context in kubeconfig
72         config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
73         if err != nil {
74                 log.Panicf("Unable to build cluster config: %v", err)
75         }
76
77         // create the clientset
78         clientset, err := kubernetes.NewForConfig(config)
79         if err != nil {
80                 log.Panicf("Unable to build client: %v", err)
81         }
82
83         // get list of nodes to extract addresses for running scan
84         nodes, err := clientset.CoreV1().Nodes().List(metav1.ListOptions{})
85         if err != nil {
86                 log.Panicf("Unable to get list of nodes: %v", err)
87         }
88
89         // filter out addresses for running scan
90         addresses, ok := ports.FilterIPAddresses(nodes)
91         if !ok {
92                 log.Println("There are no IP addresses to run scan")
93                 os.Exit(0)
94         }
95
96         // get list of services to extract nodeport information
97         services, err := clientset.CoreV1().Services("").List(metav1.ListOptions{})
98         if err != nil {
99                 log.Panicf("Unable to get list of services: %v", err)
100         }
101
102         // filter out nodeports with corresponding services from service list
103         nodeports, ok := ports.FilterNodePorts(services)
104         if !ok {
105                 log.Println("There are no NodePorts in the cluster")
106                 os.Exit(0)
107         }
108
109         // filter out expected failures here before running the scan
110         ports.FilterXFailNodePorts(xfails, nodeports)
111
112         // extract ports for running the scan
113         var ports []string
114         for port := range nodeports {
115                 ports = append(ports, strconv.Itoa(int(port)))
116         }
117
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" {
128                                 return false
129                         }
130                         if strings.HasPrefix(p.State.State, "closed") {
131                                 return false
132                         }
133                         if strings.HasPrefix(p.State.State, "filtered") {
134                                 return false
135                         }
136                         return true
137                 }),
138         )
139         if err != nil {
140                 log.Panicf("Unable to create nmap scanner: %v", err)
141         }
142
143         result, _, err := scanner.Run()
144         if err != nil {
145                 log.Panicf("Scan failed: %v", err)
146         }
147
148         // scan was run on a single host
149         if len(result.Hosts) < 1 {
150                 log.Panicln("No host information in scan results")
151         }
152
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)
157                 }
158         }
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])
162         }
163
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))
167 }