Skip to content

Commit

Permalink
Add Registry Mirrors to Trivy
Browse files Browse the repository at this point in the history
This patch adds the option to use mirrors for the docker registries in trivy.
This way it is possible to download the images from self-hosted mirrors instead
of e.g. index.docker.io. This has some benefits, like not being hit by download
restrictions.
  • Loading branch information
Sven Haardiek committed Aug 18, 2021
1 parent a8537f3 commit e8a613b
Show file tree
Hide file tree
Showing 3 changed files with 439 additions and 9 deletions.
2 changes: 2 additions & 0 deletions docs/integrations/vulnerability-scanners/trivy.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ EOF
| `trivy.serverURL` | N/A | The endpoint URL of the Trivy server. Required in `ClientServer` mode. |
| `trivy.serverTokenHeader` | `Trivy-Token` | The name of the HTTP header to send the authentication token to Trivy server. Only application in `ClientServer` mode when `trivy.serverToken` is specified. |
| `trivy.insecureRegistry.<id>` | N/A | The registry to which insecure connections are allowed. There can be multiple registries with different registry `<id>`. |
| `trivy.mirrors.registry.<id>` | N/A | A registry for which a mirror should be used to get an image. For the mirror url `trivy.mirrors.mirror.<id>` with the matching `<id>`. For each entry there must be a corresponding `trivy.mirrors.mirror.<id>` entry. There can be multiple registries with different registry `<id>`. |
| `trivy.mirrors.mirror.<id>` | N/A | The mirror for the registry with `<id>`. |
| `trivy.httpProxy` | N/A | The HTTP proxy used by Trivy to download the vulnerabilities database from GitHub. |
| `trivy.httpsProxy` | N/A | The HTTPS proxy used by Trivy to download the vulnerabilities database from GitHub. |
| `trivy.noProxy` | N/A | A comma separated list of IPs and domain names that are not subject to proxy settings. |
Expand Down
78 changes: 76 additions & 2 deletions pkg/plugin/trivy/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const (
keyTrivyIgnoreUnfixed = "trivy.ignoreUnfixed"
keyTrivyIgnoreFile = "trivy.ignoreFile"
keyTrivyInsecureRegistryPrefix = "trivy.insecureRegistry."
keyTrivyMirrorSrcPrefix = "trivy.mirrors.registry."
keyTrivyMirrorDstPrefix = "trivy.mirrors.mirror."
keyTrivyHTTPProxy = "trivy.httpProxy"
keyTrivyHTTPSProxy = "trivy.httpsProxy"
keyTrivyNoProxy = "trivy.noProxy"
Expand Down Expand Up @@ -105,6 +107,28 @@ func (c Config) GetInsecureRegistries() map[string]bool {
return insecureRegistries
}

func (c Config) GetMirrors() (map[string]string, error) {
res := make(map[string]string)
for registyKey, registry := range c.Data {
if !strings.HasPrefix(registyKey, keyTrivyMirrorSrcPrefix) {
continue
}
mirrorKey := fmt.Sprintf(
"%v%v",
keyTrivyMirrorDstPrefix,
strings.TrimPrefix(registyKey, keyTrivyMirrorSrcPrefix),
)

mirror, ok := c.Data[mirrorKey]
if !ok {
return res, fmt.Errorf("mirror %v missing for %v", mirrorKey, registyKey)
}

res[registry] = mirror
}
return res, nil
}

// GetResourceRequirements creates ResourceRequirements from the Config.
func (c Config) GetResourceRequirements() (corev1.ResourceRequirements, error) {
requirements := corev1.ResourceRequirements{
Expand Down Expand Up @@ -506,6 +530,11 @@ func (p *plugin) getPodSpecForStandaloneMode(config Config, spec corev1.PodSpec,
return corev1.PodSpec{}, nil, err
}

mirrors, err := config.GetMirrors()
if err != nil {
return corev1.PodSpec{}, nil, err
}

containers = append(containers, corev1.Container{
Name: c.Name,
Image: trivyImageRef,
Expand All @@ -522,7 +551,7 @@ func (p *plugin) getPodSpecForStandaloneMode(config Config, spec corev1.PodSpec,
"--quiet",
"--format",
"json",
c.Image,
GetMirroredImage(c.Image, mirrors),
},
Resources: resourceRequirements,
VolumeMounts: volumeMounts,
Expand Down Expand Up @@ -776,6 +805,11 @@ func (p *plugin) getPodSpecForClientServerMode(config Config, spec corev1.PodSpe
return corev1.PodSpec{}, nil, err
}

mirrors, err := config.GetMirrors()
if err != nil {
return corev1.PodSpec{}, nil, err
}

containers = append(containers, corev1.Container{
Name: container.Name,
Image: trivyImageRef,
Expand All @@ -792,7 +826,7 @@ func (p *plugin) getPodSpecForClientServerMode(config Config, spec corev1.PodSpe
"json",
"--remote",
trivyServerURL,
container.Image,
GetMirroredImage(container.Image, mirrors),
},
VolumeMounts: volumeMounts,
Resources: requirements,
Expand Down Expand Up @@ -946,3 +980,43 @@ func GetScoreFromCVSS(CVSSs map[string]*CVSS) *float64 {

return nvdScore
}

func fullImagePath(image string) string {
const defaultRegistry = "index.docker.io"
registryAndImage := strings.Split(image, "/")
// Empty string
if len(registryAndImage) == 0 {
return image
}

// Add default Registry, if none is present
if len(registryAndImage) == 1 ||
!(strings.Contains(registryAndImage[0], ".") ||
strings.Contains(registryAndImage[0], ":") ||
registryAndImage[0] == "localhost") {
registryAndImage = append([]string{defaultRegistry}, registryAndImage...)
}

// Add "library" if only image name is given and registry is DockerHub
if len(registryAndImage) == 2 &&
(strings.HasSuffix(registryAndImage[0], "docker.io") ||
strings.HasSuffix(registryAndImage[0], "docker.com")) {
registryAndImage = append(registryAndImage[:2], registryAndImage[1:]...)
registryAndImage[1] = "library"
}

return strings.Join(registryAndImage, "/")
}

func GetMirroredImage(image string, mirrors map[string]string) string {
mirroredImage := fullImagePath(image)

for k, v := range mirrors {
if strings.HasPrefix(mirroredImage, k) {
mirroredImage = strings.Replace(mirroredImage, k, v, 1)
return mirroredImage
}
}
// If nothing is mirrord, we can simply use the input image without the fullpath.
return image
}
Loading

0 comments on commit e8a613b

Please sign in to comment.