Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Registry Mirrors to Trivy #673

Merged
merged 2 commits into from
Sep 13, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>`. |
shaardie marked this conversation as resolved.
Show resolved Hide resolved
| `trivy.mirrors.mirror.<id>` | N/A | The mirror for the registry with `<id>`. |
shaardie marked this conversation as resolved.
Show resolved Hide resolved
| `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 {
shaardie marked this conversation as resolved.
Show resolved Hide resolved
if !strings.HasPrefix(registyKey, keyTrivyMirrorSrcPrefix) {
continue
}
mirrorKey := fmt.Sprintf(
"%v%v",
danielpacak marked this conversation as resolved.
Show resolved Hide resolved
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, "/")
shaardie marked this conversation as resolved.
Show resolved Hide resolved
// 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