mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-22 23:26:39 -08:00
146 lines
4.0 KiB
Go
146 lines
4.0 KiB
Go
package scanner
|
|
|
|
import (
|
|
"context"
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/aquasecurity/trivy-kubernetes/pkg/artifacts"
|
|
cmd "github.com/aquasecurity/trivy/pkg/commands/artifact"
|
|
"github.com/aquasecurity/trivy/pkg/flag"
|
|
"github.com/aquasecurity/trivy/pkg/k8s/report"
|
|
"github.com/aquasecurity/trivy/pkg/log"
|
|
"github.com/aquasecurity/trivy/pkg/parallel"
|
|
"github.com/aquasecurity/trivy/pkg/scanner/local"
|
|
"github.com/aquasecurity/trivy/pkg/types"
|
|
)
|
|
|
|
type Scanner struct {
|
|
cluster string
|
|
runner cmd.Runner
|
|
opts flag.Options
|
|
}
|
|
|
|
func NewScanner(cluster string, runner cmd.Runner, opts flag.Options) *Scanner {
|
|
return &Scanner{
|
|
cluster,
|
|
runner,
|
|
opts,
|
|
}
|
|
}
|
|
|
|
func (s *Scanner) Scan(ctx context.Context, artifactsData []*artifacts.Artifact) (report.Report, error) {
|
|
|
|
// disable logs before scanning
|
|
err := log.InitLogger(s.opts.Debug, true)
|
|
if err != nil {
|
|
return report.Report{}, xerrors.Errorf("logger error: %w", err)
|
|
}
|
|
|
|
// enable log, this is done in a defer function,
|
|
// to enable logs even when the function returns earlier
|
|
// due to an error
|
|
defer func() {
|
|
err = log.InitLogger(s.opts.Debug, false)
|
|
if err != nil {
|
|
// we use log.Fatal here because the error was to enable the logger
|
|
log.Fatal(xerrors.Errorf("can't enable logger error: %w", err))
|
|
}
|
|
}()
|
|
var resources []report.Resource
|
|
|
|
type scanResult struct {
|
|
vulns []report.Resource
|
|
misconfig report.Resource
|
|
}
|
|
|
|
onItem := func(ctx context.Context, artifact *artifacts.Artifact) (scanResult, error) {
|
|
scanResults := scanResult{}
|
|
if s.opts.Scanners.AnyEnabled(types.VulnerabilityScanner, types.SecretScanner) {
|
|
vulns, err := s.scanVulns(ctx, artifact)
|
|
if err != nil {
|
|
return scanResult{}, xerrors.Errorf("scanning vulnerabilities error: %w", err)
|
|
}
|
|
scanResults.vulns = vulns
|
|
}
|
|
if local.ShouldScanMisconfigOrRbac(s.opts.Scanners) {
|
|
misconfig, err := s.scanMisconfigs(ctx, artifact)
|
|
if err != nil {
|
|
return scanResult{}, xerrors.Errorf("scanning misconfigurations error: %w", err)
|
|
}
|
|
scanResults.misconfig = misconfig
|
|
}
|
|
return scanResults, nil
|
|
}
|
|
|
|
onResult := func(result scanResult) error {
|
|
resources = append(resources, result.vulns...)
|
|
resources = append(resources, result.misconfig)
|
|
return nil
|
|
}
|
|
|
|
p := parallel.NewPipeline(s.opts.Parallel, !s.opts.Quiet, artifactsData, onItem, onResult)
|
|
err = p.Do(ctx)
|
|
if err != nil {
|
|
return report.Report{}, err
|
|
}
|
|
return report.Report{
|
|
SchemaVersion: 0,
|
|
ClusterName: s.cluster,
|
|
Resources: resources,
|
|
}, nil
|
|
}
|
|
|
|
func (s *Scanner) scanVulns(ctx context.Context, artifact *artifacts.Artifact) ([]report.Resource, error) {
|
|
resources := make([]report.Resource, 0, len(artifact.Images))
|
|
|
|
for _, image := range artifact.Images {
|
|
|
|
s.opts.Target = image
|
|
|
|
imageReport, err := s.runner.ScanImage(ctx, s.opts)
|
|
|
|
if err != nil {
|
|
log.Logger.Warnf("failed to scan image %s: %s", image, err)
|
|
resources = append(resources, report.CreateResource(artifact, imageReport, err))
|
|
continue
|
|
}
|
|
|
|
resource, err := s.filter(ctx, imageReport, artifact)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("filter error: %w", err)
|
|
}
|
|
|
|
resources = append(resources, resource)
|
|
}
|
|
|
|
return resources, nil
|
|
}
|
|
|
|
func (s *Scanner) scanMisconfigs(ctx context.Context, artifact *artifacts.Artifact) (report.Resource, error) {
|
|
configFile, err := createTempFile(artifact)
|
|
if err != nil {
|
|
return report.Resource{}, xerrors.Errorf("scan error: %w", err)
|
|
}
|
|
|
|
s.opts.Target = configFile
|
|
|
|
configReport, err := s.runner.ScanFilesystem(ctx, s.opts)
|
|
//remove config file after scanning
|
|
removeFile(configFile)
|
|
if err != nil {
|
|
log.Logger.Debugf("failed to scan config %s/%s: %s", artifact.Kind, artifact.Name, err)
|
|
return report.CreateResource(artifact, configReport, err), err
|
|
}
|
|
|
|
return s.filter(ctx, configReport, artifact)
|
|
}
|
|
func (s *Scanner) filter(ctx context.Context, r types.Report, artifact *artifacts.Artifact) (report.Resource, error) {
|
|
var err error
|
|
r, err = s.runner.Filter(ctx, s.opts, r)
|
|
if err != nil {
|
|
return report.Resource{}, xerrors.Errorf("filter error: %w", err)
|
|
}
|
|
return report.CreateResource(artifact, r, nil), nil
|
|
}
|