mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 07:40:48 -08:00
177 lines
4.7 KiB
Go
177 lines
4.7 KiB
Go
package scanner
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io/fs"
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
aws "github.com/aquasecurity/trivy-aws/pkg/scanner"
|
|
"github.com/aquasecurity/trivy/pkg/cloud/aws/cache"
|
|
"github.com/aquasecurity/trivy/pkg/commands/operation"
|
|
"github.com/aquasecurity/trivy/pkg/flag"
|
|
"github.com/aquasecurity/trivy/pkg/iac/framework"
|
|
"github.com/aquasecurity/trivy/pkg/iac/scan"
|
|
"github.com/aquasecurity/trivy/pkg/iac/scanners/options"
|
|
"github.com/aquasecurity/trivy/pkg/iac/state"
|
|
"github.com/aquasecurity/trivy/pkg/log"
|
|
"github.com/aquasecurity/trivy/pkg/misconf"
|
|
)
|
|
|
|
type AWSScanner struct {
|
|
logger *log.Logger
|
|
}
|
|
|
|
func NewScanner() *AWSScanner {
|
|
return &AWSScanner{
|
|
logger: log.WithPrefix("aws"),
|
|
}
|
|
}
|
|
|
|
func (s *AWSScanner) Scan(ctx context.Context, option flag.Options) (scan.Results, bool, error) {
|
|
|
|
awsCache := cache.New(option.CacheDir, option.MaxCacheAge, option.Account, option.Region)
|
|
included, missing := awsCache.ListServices(option.Services)
|
|
|
|
prefixedLogger := log.NewWriteLogger(log.WithPrefix("aws"))
|
|
|
|
var scannerOpts []options.ScannerOption
|
|
if !option.NoProgress {
|
|
tracker := newProgressTracker(prefixedLogger)
|
|
defer tracker.Finish()
|
|
scannerOpts = append(scannerOpts, aws.ScannerWithProgressTracker(tracker))
|
|
}
|
|
|
|
if len(missing) > 0 {
|
|
scannerOpts = append(scannerOpts, aws.ScannerWithAWSServices(missing...))
|
|
}
|
|
|
|
if option.Debug {
|
|
scannerOpts = append(scannerOpts, options.ScannerWithDebug(prefixedLogger))
|
|
}
|
|
|
|
if option.Trace {
|
|
scannerOpts = append(scannerOpts, options.ScannerWithTrace(prefixedLogger))
|
|
}
|
|
|
|
if option.Region != "" {
|
|
scannerOpts = append(
|
|
scannerOpts,
|
|
aws.ScannerWithAWSRegion(option.Region),
|
|
)
|
|
}
|
|
|
|
if option.Endpoint != "" {
|
|
scannerOpts = append(
|
|
scannerOpts,
|
|
aws.ScannerWithAWSEndpoint(option.Endpoint),
|
|
)
|
|
}
|
|
|
|
var policyPaths []string
|
|
var downloadedPolicyPaths []string
|
|
var err error
|
|
|
|
downloadedPolicyPaths, err = operation.InitBuiltinPolicies(context.Background(), option.CacheDir, option.Quiet, option.SkipCheckUpdate, option.MisconfOptions.ChecksBundleRepository, option.RegistryOpts())
|
|
if err != nil {
|
|
if !option.SkipCheckUpdate {
|
|
s.logger.Error("Falling back to embedded checks", log.Err(err))
|
|
}
|
|
} else {
|
|
s.logger.Debug("Checks successfully loaded from disk")
|
|
policyPaths = append(policyPaths, downloadedPolicyPaths...)
|
|
scannerOpts = append(scannerOpts,
|
|
options.ScannerWithEmbeddedPolicies(false),
|
|
options.ScannerWithEmbeddedLibraries(false))
|
|
}
|
|
|
|
var policyFS fs.FS
|
|
policyFS, policyPaths, err = misconf.CreatePolicyFS(append(policyPaths, option.RegoOptions.CheckPaths...))
|
|
if err != nil {
|
|
return nil, false, xerrors.Errorf("unable to create policyfs: %w", err)
|
|
}
|
|
|
|
scannerOpts = append(scannerOpts,
|
|
options.ScannerWithPolicyFilesystem(policyFS),
|
|
options.ScannerWithPolicyDirs(policyPaths...),
|
|
)
|
|
|
|
dataFS, dataPaths, err := misconf.CreateDataFS(option.RegoOptions.DataPaths)
|
|
if err != nil {
|
|
s.logger.Error("Could not load config data", log.Err(err))
|
|
}
|
|
scannerOpts = append(scannerOpts,
|
|
options.ScannerWithDataDirs(dataPaths...),
|
|
options.ScannerWithDataFilesystem(dataFS),
|
|
)
|
|
|
|
scannerOpts = addPolicyNamespaces(option.RegoOptions.CheckNamespaces, scannerOpts)
|
|
|
|
if option.Compliance.Spec.ID != "" {
|
|
scannerOpts = append(scannerOpts, options.ScannerWithSpec(option.Compliance.Spec.ID))
|
|
} else {
|
|
scannerOpts = append(scannerOpts, options.ScannerWithFrameworks(
|
|
framework.Default,
|
|
framework.CIS_AWS_1_2))
|
|
}
|
|
|
|
scanner := aws.New(scannerOpts...)
|
|
|
|
var freshState *state.State
|
|
if len(missing) > 0 || option.CloudOptions.UpdateCache {
|
|
var err error
|
|
freshState, err = scanner.CreateState(ctx)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
}
|
|
|
|
fullState, err := createState(freshState, awsCache)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
if fullState == nil {
|
|
return nil, false, fmt.Errorf("no resultant state found")
|
|
}
|
|
|
|
if err := awsCache.AddServices(fullState, missing); err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
defsecResults, err := scanner.Scan(ctx, fullState)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
return defsecResults, len(included) > 0, nil
|
|
}
|
|
|
|
func createState(freshState *state.State, awsCache *cache.Cache) (*state.State, error) {
|
|
var fullState *state.State
|
|
if previousState, err := awsCache.LoadState(); err == nil {
|
|
if freshState != nil {
|
|
fullState, err = previousState.Merge(freshState)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
fullState = previousState
|
|
}
|
|
} else {
|
|
fullState = freshState
|
|
}
|
|
return fullState, nil
|
|
}
|
|
|
|
func addPolicyNamespaces(namespaces []string, scannerOpts []options.ScannerOption) []options.ScannerOption {
|
|
if len(namespaces) > 0 {
|
|
scannerOpts = append(
|
|
scannerOpts,
|
|
options.ScannerWithPolicyNamespaces(namespaces...),
|
|
)
|
|
}
|
|
return scannerOpts
|
|
}
|