-
Notifications
You must be signed in to change notification settings - Fork 153
/
scanner.go
102 lines (84 loc) · 3.43 KB
/
scanner.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package main
import (
"context"
"os"
"strings"
)
type vulnerabilitiesWhitelist struct {
GeneralWhitelist map[string]string //[key: CVE and value: CVE description]
Images map[string]map[string]string // image name with [key: CVE and value: CVE description]
}
const tmpPrefix = "clair-scanner-"
type scannerConfig struct {
imageName string
whitelist vulnerabilitiesWhitelist
clairURL string
scannerIP string
reportFile string
whitelistThreshold string
reportAll bool
quiet bool
exitWhenNoFeatures bool
}
// scan orchestrates the scanning process of an image
func scan(config scannerConfig) []string {
//Create a temporary folder where the docker image layers are going to be stored
tmpPath := createTmpPath(tmpPrefix)
defer os.RemoveAll(tmpPath)
saveDockerImage(config.imageName, tmpPath)
layerIds := getImageLayerIds(tmpPath)
//Start a server that can serve Docker image layers to Clair
server := httpFileServer(tmpPath)
defer server.Shutdown(context.TODO())
//Analyze the layers
analyzeLayers(layerIds, config.clairURL, config.scannerIP)
vulnerabilities := getVulnerabilities(config, layerIds)
if vulnerabilities == nil {
return nil // exit when no features
}
//Check vulnerabilities against whitelist and report
unapproved := checkForUnapprovedVulnerabilities(config.imageName, vulnerabilities, config.whitelist, config.whitelistThreshold)
// Report vulnerabilities
reportToConsole(config.imageName, vulnerabilities, unapproved, config.reportAll, config.quiet)
reportToFile(config.imageName, vulnerabilities, unapproved, config.reportFile)
return unapproved
}
// checkForUnapprovedVulnerabilities checks if the found vulnerabilities are approved or not in the whitelist
func checkForUnapprovedVulnerabilities(imageName string, vulnerabilities []vulnerabilityInfo, whitelist vulnerabilitiesWhitelist, whitelistThreshold string) []string {
unapproved := []string{}
imageVulnerabilities := getImageVulnerabilities(imageName, whitelist.Images)
for i := 0; i < len(vulnerabilities); i++ {
vulnerability := vulnerabilities[i].Vulnerability
severity := vulnerabilities[i].Severity
vulnerable := true
//Check if the vulnerability has a severity less than our threshold severity
if SeverityMap[severity] > SeverityMap[whitelistThreshold] {
vulnerable = false
}
//Check if the vulnerability exists in the GeneralWhitelist
if vulnerable {
if _, exists := whitelist.GeneralWhitelist[vulnerability]; exists {
vulnerable = false
}
}
//If not in GeneralWhitelist check if the vulnerability exists in the imageVulnerabilities
if vulnerable && len(imageVulnerabilities) > 0 {
if _, exists := imageVulnerabilities[vulnerability]; exists {
vulnerable = false
}
}
if vulnerable {
unapproved = append(unapproved, vulnerability)
}
}
return unapproved
}
// getImageVulnerabilities returns image specific whitelist of vulnerabilities from whitelistImageVulnerabilities
func getImageVulnerabilities(imageName string, whitelistImageVulnerabilities map[string]map[string]string) map[string]string {
var imageVulnerabilities map[string]string
imageWithoutVersion := strings.Split(imageName, ":") // TODO there is a bug here if it is a private registry with a custom port registry:777/ubuntu:tag
if val, exists := whitelistImageVulnerabilities[imageWithoutVersion[0]]; exists {
imageVulnerabilities = val
}
return imageVulnerabilities
}