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

feat: use trivy as a binary instead of a library #786

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
# syntax=mcr.microsoft.com/oss/moby/dockerfile:1.5.1

ARG BUILDERIMAGE="golang:1.20-bullseye"
ARG TRIVY_BINARY_IMG="ghcr.io/aquasecurity/trivy:0.43.0"
ARG STATICBASEIMAGE="gcr.io/distroless/static:latest"
ARG STATICNONROOTBASEIMAGE="gcr.io/distroless/static:nonroot"
ARG BUILDKIT_SBOM_SCAN_STAGE=builder,manager-build,collector-build,remover-build,trivy-scanner-build

FROM --platform=$TARGETPLATFORM $TRIVY_BINARY_IMG AS trivy-binary

# Build the manager binary
FROM --platform=$BUILDPLATFORM $BUILDERIMAGE AS builder
WORKDIR /workspace
Expand Down Expand Up @@ -65,6 +68,7 @@ ENTRYPOINT ["/remover"]

FROM --platform=$TARGETPLATFORM $STATICBASEIMAGE as trivy-scanner
COPY --from=trivy-scanner-build /workspace/out/trivy-scanner /
COPY --from=trivy-binary /usr/local/bin/trivy /
WORKDIR /var/lib/trivy
ENTRYPOINT ["/trivy-scanner"]

Expand Down
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ REMOVER_TAG ?= ${VERSION}
# Image URL to use all building/pushing image targets
TRIVY_SCANNER_REPO ?= ghcr.io/azure/eraser-trivy-scanner
TRIVY_SCANNER_IMG ?= ${TRIVY_SCANNER_REPO}:${TRIVY_SCANNER_TAG}
TRIVY_BINARY_REPO ?= ghcr.io/aquasecurity/trivy
TRIVY_BINARY_TAG ?= 0.43.0
TRIVY_BINARY_IMG ?= ${TRIVY_BINARY_REPO}:${TRIVY_BINARY_TAG}
MANAGER_REPO ?= ghcr.io/azure/eraser-manager
MANAGER_IMG ?= ${MANAGER_REPO}:${MANAGER_TAG}
REMOVER_REPO ?= ghcr.io/azure/remover
Expand All @@ -34,14 +37,13 @@ KUBERNETES_VERSION ?= 1.25.3
NODE_VERSION ?= 16-bullseye-slim
ENVTEST_K8S_VERSION ?= 1.25
GOLANGCI_LINT_VERSION := 1.43.0
TRIVY_VERSION ?= $(shell go list -f '{{ .Version }}' -m github.com/aquasecurity/trivy)

PLATFORM ?= linux

# build variables
LDFLAGS ?= $(shell build/version.sh "${VERSION}")
ERASER_LDFLAGS ?= -extldflags=-static $(LDFLAGS) -w
TRIVY_SCANNER_LDFLAGS ?= $(ERASER_LDFLAGS) -X 'main.trivyVersion=$(TRIVY_VERSION)'
TRIVY_SCANNER_LDFLAGS ?= $(ERASER_LDFLAGS) -X 'main.trivyVersion=v$(TRIVY_BINARY_TAG)'

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
Expand Down Expand Up @@ -212,6 +214,7 @@ docker-build-trivy-scanner: ## Build docker image for trivy-scanner image.
docker buildx build \
$(_CACHE_FROM) $(_CACHE_TO) \
$(_ATTESTATIONS) \
--build-arg TRIVY_BINARY_IMG="$(TRIVY_BINARY_IMG)" \
--build-arg LDFLAGS="$(TRIVY_SCANNER_LDFLAGS)" \
--platform="$(PLATFORM)" \
--output=$(OUTPUT_TYPE) \
Expand Down
226 changes: 5 additions & 221 deletions go.mod

Large diffs are not rendered by default.

1,777 changes: 6 additions & 1,771 deletions go.sum

Large diffs are not rendered by default.

113 changes: 0 additions & 113 deletions pkg/scanners/trivy/helpers.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,9 @@
package main

import (
"context"
"fmt"
"os"
"strings"

unversioned "github.com/Azure/eraser/api/unversioned"
"github.com/aquasecurity/trivy-db/pkg/db"
dlDb "github.com/aquasecurity/trivy/pkg/db"
"github.com/aquasecurity/trivy/pkg/detector/ospkg"
"github.com/aquasecurity/trivy/pkg/fanal/applier"
"github.com/aquasecurity/trivy/pkg/fanal/cache"
fanalTypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/scanner/local"
trivyTypes "github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/vulnerability"
"k8s.io/apimachinery/pkg/util/yaml"
)

Expand Down Expand Up @@ -46,104 +34,3 @@ func loadConfig(filename string) (Config, error) {

return cfg, nil
}

// side effects: map `m` will be modified according to the values in `commaSeparatedList`.
func parseCommaSeparatedOptions(m map[string]bool, commaSeparatedList string) error {
list := strings.Split(commaSeparatedList, ",")
for _, item := range list {
if _, ok := m[item]; !ok {
keys := mapKeys(m)
return fmt.Errorf("'%s' was not one of %#v", item, keys)
}

m[item] = true
}

return nil
}

func downloadAndInitDB(cfg *Config) error {
if cfg == nil {
return fmt.Errorf("valid configuration required")
}

err := downloadDB(cfg)
if err != nil {
return err
}

err = db.Init(cfg.CacheDir)
if err != nil {
return err
}

return nil
}

func downloadDB(cfg *Config) error {
if cfg == nil {
return fmt.Errorf("valid configuration required")
}

client := dlDb.NewClient(cfg.CacheDir, true, true, dlDb.WithDBRepository(cfg.DBRepo))
ctx := context.Background()
needsUpdate, err := client.NeedsUpdate(trivyVersion, false)
if err != nil {
return err
}

if needsUpdate {
if err = client.Download(ctx, cfg.CacheDir); err != nil {
return err
}
}

return nil
}

func setupScanner(cacheDir string, vulnTypes, securityChecks []string) (scannerSetup, error) {
filesystemCache, err := cache.NewFSCache(cacheDir)
if err != nil {
return scannerSetup{}, err
}

app := applier.NewApplier(filesystemCache)
det := ospkg.Detector{}
dopts := fanalTypes.DockerOption{}
vc := vulnerability.NewClient(db.Config{})
scan := local.NewScanner(app, det, vc)

sopts := trivyTypes.ScanOptions{
VulnType: vulnTypes,
SecurityChecks: securityChecks,
ScanRemovedPackages: false,
ListAllPackages: false,
}

return scannerSetup{
localScanner: scan,
scanOptions: sopts,
dockerOptions: dopts,
fscache: filesystemCache,
}, nil
}

func mapKeys(m map[string]bool) []string {
list := []string{}
for k := range m {
list = append(list, k)
}

return list
}

func trueMapKeys(m map[string]bool) []string {
list := []string{}
for k := range m {
if m[k] {
list = append(list, k)
}
}

return list
}
115 changes: 6 additions & 109 deletions pkg/scanners/trivy/trivy.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"github.com/Azure/eraser/pkg/logger"
"github.com/Azure/eraser/pkg/scanners/template"
"github.com/Azure/eraser/pkg/utils"
fanalImage "github.com/aquasecurity/trivy/pkg/fanal/image"
trivylogger "github.com/aquasecurity/trivy/pkg/log"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)
Expand All @@ -44,52 +43,6 @@ var (
enableProfile = flag.Bool("enable-pprof", false, "enable pprof profiling")
profilePort = flag.Int("pprof-port", 6060, "port for pprof profiling. defaulted to 6060 if unspecified")

// Will be modified by parseCommaSeparatedOptions() to reflect the
// `severity` CLI flag These are the only recognized severities and the
// keys of this map should never be modified.
severityMap = map[string]bool{
severityCritical: false,
severityHigh: false,
severityMedium: false,
severityLow: false,
severityUnknown: false,
}

// Will be modified by parseCommaSeparatedOptions() to reflect the
// `security-checks` CLI flag These are the only recognized security checks
// and the keys of this map should never be modified.
securityCheckMap = map[string]bool{
securityCheckVuln: false,
securityCheckSecret: false,
securityCheckConfig: false,
}

// Will be modified by parseCommaSeparatedOptions() to reflect the
// `vuln-type` CLI flag These are the only recognized vulnerability types
// and the keys of this map should never be modified.
vulnTypeMap = map[string]bool{
vulnTypeOs: false,
vulnTypeLibrary: false,
}

runtimeFanalOptionsMap = map[string][]fanalImage.Option{
utils.RuntimeDocker: {
fanalImage.DisableRemote(),
fanalImage.DisableContainerd(),
fanalImage.DisablePodman(),
},
utils.RuntimeContainerd: {
fanalImage.DisableRemote(),
fanalImage.DisableDockerd(),
fanalImage.DisablePodman(),
},
utils.RuntimeCrio: {
fanalImage.DisableRemote(),
fanalImage.DisableContainerd(),
fanalImage.DisableDockerd(),
},
}

log = logf.Log.WithName("scanner").WithValues("provider", "trivy")

// This can be overwritten by the linker.
Expand All @@ -105,6 +58,7 @@ func main() {
os.Exit(generalErr)
}

log.Info("trivy version", "trivy version", trivyVersion)
log.Info("config", "config", *config)

userConfig := *DefaultConfig()
Expand All @@ -122,13 +76,6 @@ func main() {
"struct", fmt.Sprintf("%#v\n", userConfig),
)

// Initializes logger and parses CLI options into hashmap configs
err = initGlobals(&userConfig.Vulnerabilities)
if err != nil {
fmt.Fprintf(os.Stderr, "error initializing options: %v", err)
os.Exit(generalErr)
}

if *enableProfile {
go runProfileServer()
}
Expand Down Expand Up @@ -183,40 +130,6 @@ func main() {
log.Info("remover job completed, shutting down...")
}

// Initializes logger and parses CLI options into hashmap configs.
func initGlobals(cfg *VulnConfig) error {
if cfg == nil {
return fmt.Errorf("valid configuration required")
}

allSetsOfCommaSeparatedOptions := []optionSet{
{
input: cfg.Severities,
m: severityMap,
},
{
input: cfg.Types,
m: vulnTypeMap,
},
{
input: cfg.SecurityChecks,
m: securityCheckMap,
},
}

for _, oSet := range allSetsOfCommaSeparatedOptions {
fillMap(oSet.input, oSet.m)
}

return nil
}

func fillMap(sl []string, m map[string]bool) {
for _, s := range sl {
m[s] = true
}
}

func runProfileServer() {
server := &http.Server{
Addr: fmt.Sprintf("localhost:%d", *profilePort),
Expand All @@ -231,12 +144,6 @@ func initScanner(userConfig *Config) (Scanner, error) {
return nil, fmt.Errorf("invalid trivy scanner config")
}

cacheDir := userConfig.CacheDir
err := downloadAndInitDB(userConfig)
if err != nil {
return nil, fmt.Errorf("unable to initialize trivy db. cacheDir: %s, error: %w", cacheDir, err)
}

logger, err := zap.NewProduction()
if err != nil {
return nil, fmt.Errorf("error setting up trivy logger: %w", err)
Expand All @@ -245,28 +152,18 @@ func initScanner(userConfig *Config) (Scanner, error) {
sugar := logger.Sugar()
trivylogger.Logger = sugar

vulnTypeList := trueMapKeys(vulnTypeMap)
securityCheckList := trueMapKeys(securityCheckMap)

scanConfig, err := setupScanner(cacheDir, vulnTypeList, securityCheckList)
if err != nil {
return nil, err
}

runtime := os.Getenv(utils.EnvEraserContainerRuntime)
imageSourceOptions, ok := runtimeFanalOptionsMap[runtime]
if !ok {
return nil, fmt.Errorf("unable to determine runtime from environment: %w", err)
if runtime == "" {
runtime = utils.RuntimeContainerd
}

userConfig.Runtime = runtime
totalTimeout := time.Duration(userConfig.Timeout.Total)
timer := time.NewTimer(totalTimeout)

var s Scanner = &ImageScanner{
trivyScanConfig: scanConfig,
imageSourceOptions: imageSourceOptions,
userConfig: *userConfig,
timer: timer,
config: *userConfig,
timer: timer,
}
return s, nil
}
Expand Down
Loading
Loading