github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/cloud/aws/scanner/scanner.go (about)

     1  package scanner
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io/fs"
     7  
     8  	"golang.org/x/xerrors"
     9  
    10  	"github.com/aquasecurity/defsec/pkg/framework"
    11  	"github.com/aquasecurity/defsec/pkg/scan"
    12  	"github.com/aquasecurity/defsec/pkg/scanners/options"
    13  	"github.com/aquasecurity/defsec/pkg/state"
    14  	aws "github.com/aquasecurity/trivy-aws/pkg/scanner"
    15  	"github.com/devseccon/trivy/pkg/cloud/aws/cache"
    16  	"github.com/devseccon/trivy/pkg/commands/operation"
    17  	"github.com/devseccon/trivy/pkg/flag"
    18  	"github.com/devseccon/trivy/pkg/log"
    19  	"github.com/devseccon/trivy/pkg/misconf"
    20  )
    21  
    22  type AWSScanner struct {
    23  }
    24  
    25  func NewScanner() *AWSScanner {
    26  	return &AWSScanner{}
    27  }
    28  
    29  func (s *AWSScanner) Scan(ctx context.Context, option flag.Options) (scan.Results, bool, error) {
    30  
    31  	awsCache := cache.New(option.CacheDir, option.MaxCacheAge, option.Account, option.Region)
    32  	included, missing := awsCache.ListServices(option.Services)
    33  
    34  	var scannerOpts []options.ScannerOption
    35  	if !option.NoProgress {
    36  		tracker := newProgressTracker()
    37  		defer tracker.Finish()
    38  		scannerOpts = append(scannerOpts, aws.ScannerWithProgressTracker(tracker))
    39  	}
    40  
    41  	if len(missing) > 0 {
    42  		scannerOpts = append(scannerOpts, aws.ScannerWithAWSServices(missing...))
    43  	}
    44  
    45  	if option.Debug {
    46  		scannerOpts = append(scannerOpts, options.ScannerWithDebug(&log.PrefixedLogger{Name: "aws"}))
    47  	}
    48  
    49  	if option.Trace {
    50  		scannerOpts = append(scannerOpts, options.ScannerWithTrace(&log.PrefixedLogger{Name: "aws"}))
    51  	}
    52  
    53  	if option.Region != "" {
    54  		scannerOpts = append(
    55  			scannerOpts,
    56  			aws.ScannerWithAWSRegion(option.Region),
    57  		)
    58  	}
    59  
    60  	if option.Endpoint != "" {
    61  		scannerOpts = append(
    62  			scannerOpts,
    63  			aws.ScannerWithAWSEndpoint(option.Endpoint),
    64  		)
    65  	}
    66  
    67  	var policyPaths []string
    68  	var downloadedPolicyPaths []string
    69  	var err error
    70  	downloadedPolicyPaths, err = operation.InitBuiltinPolicies(context.Background(), option.CacheDir, option.Quiet, option.SkipPolicyUpdate, option.MisconfOptions.PolicyBundleRepository)
    71  	if err != nil {
    72  		if !option.SkipPolicyUpdate {
    73  			log.Logger.Errorf("Falling back to embedded policies: %s", err)
    74  		}
    75  	} else {
    76  		log.Logger.Debug("Policies successfully loaded from disk")
    77  		policyPaths = append(policyPaths, downloadedPolicyPaths...)
    78  		scannerOpts = append(scannerOpts,
    79  			options.ScannerWithEmbeddedPolicies(false),
    80  			options.ScannerWithEmbeddedLibraries(false))
    81  	}
    82  
    83  	var policyFS fs.FS
    84  	policyFS, policyPaths, err = misconf.CreatePolicyFS(append(policyPaths, option.RegoOptions.PolicyPaths...))
    85  	if err != nil {
    86  		return nil, false, xerrors.Errorf("unable to create policyfs: %w", err)
    87  	}
    88  
    89  	scannerOpts = append(scannerOpts,
    90  		options.ScannerWithPolicyFilesystem(policyFS),
    91  		options.ScannerWithPolicyDirs(policyPaths...),
    92  	)
    93  
    94  	dataFS, dataPaths, err := misconf.CreateDataFS(option.RegoOptions.DataPaths)
    95  	if err != nil {
    96  		log.Logger.Errorf("Could not load config data: %s", err)
    97  	}
    98  	scannerOpts = append(scannerOpts,
    99  		options.ScannerWithDataDirs(dataPaths...),
   100  		options.ScannerWithDataFilesystem(dataFS),
   101  	)
   102  
   103  	scannerOpts = addPolicyNamespaces(option.RegoOptions.PolicyNamespaces, scannerOpts)
   104  
   105  	if option.Compliance.Spec.ID != "" {
   106  		scannerOpts = append(scannerOpts, options.ScannerWithSpec(option.Compliance.Spec.ID))
   107  	} else {
   108  		scannerOpts = append(scannerOpts, options.ScannerWithFrameworks(
   109  			framework.Default,
   110  			framework.CIS_AWS_1_2))
   111  	}
   112  
   113  	scanner := aws.New(scannerOpts...)
   114  
   115  	var freshState *state.State
   116  	if len(missing) > 0 || option.CloudOptions.UpdateCache {
   117  		var err error
   118  		freshState, err = scanner.CreateState(ctx)
   119  		if err != nil {
   120  			return nil, false, err
   121  		}
   122  	}
   123  
   124  	fullState, err := createState(freshState, awsCache)
   125  	if err != nil {
   126  		return nil, false, err
   127  	}
   128  
   129  	if fullState == nil {
   130  		return nil, false, fmt.Errorf("no resultant state found")
   131  	}
   132  
   133  	if err := awsCache.AddServices(fullState, missing); err != nil {
   134  		return nil, false, err
   135  	}
   136  
   137  	defsecResults, err := scanner.Scan(ctx, fullState)
   138  	if err != nil {
   139  		return nil, false, err
   140  	}
   141  
   142  	return defsecResults, len(included) > 0, nil
   143  }
   144  
   145  func createState(freshState *state.State, awsCache *cache.Cache) (*state.State, error) {
   146  	var fullState *state.State
   147  	if previousState, err := awsCache.LoadState(); err == nil {
   148  		if freshState != nil {
   149  			fullState, err = previousState.Merge(freshState)
   150  			if err != nil {
   151  				return nil, err
   152  			}
   153  		} else {
   154  			fullState = previousState
   155  		}
   156  	} else {
   157  		fullState = freshState
   158  	}
   159  	return fullState, nil
   160  }
   161  
   162  func addPolicyNamespaces(namespaces []string, scannerOpts []options.ScannerOption) []options.ScannerOption {
   163  	if len(namespaces) > 0 {
   164  		scannerOpts = append(
   165  			scannerOpts,
   166  			options.ScannerWithPolicyNamespaces(namespaces...),
   167  		)
   168  	}
   169  	return scannerOpts
   170  }