github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/pkg/scanners/cloud/aws/scanner.go (about)

     1  package aws
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"io/fs"
     9  	"os"
    10  	"runtime"
    11  	"sync"
    12  
    13  	adapter "github.com/khulnasoft-lab/defsec/internal/adapters/cloud"
    14  	cloudoptions "github.com/khulnasoft-lab/defsec/internal/adapters/cloud/options"
    15  	"github.com/khulnasoft-lab/defsec/pkg/errs"
    16  
    17  	"github.com/khulnasoft-lab/defsec/pkg/state"
    18  
    19  	"github.com/khulnasoft-lab/defsec/pkg/rego"
    20  	"github.com/khulnasoft-lab/defsec/pkg/types"
    21  
    22  	"github.com/khulnasoft-lab/defsec/internal/adapters/cloud/aws"
    23  	"github.com/khulnasoft-lab/defsec/internal/rules"
    24  	"github.com/khulnasoft-lab/defsec/pkg/concurrency"
    25  	"github.com/khulnasoft-lab/defsec/pkg/debug"
    26  	"github.com/khulnasoft-lab/defsec/pkg/framework"
    27  	"github.com/khulnasoft-lab/defsec/pkg/progress"
    28  	_ "github.com/khulnasoft-lab/defsec/pkg/rules"
    29  	"github.com/khulnasoft-lab/defsec/pkg/scan"
    30  	"github.com/khulnasoft-lab/defsec/pkg/scanners/options"
    31  )
    32  
    33  var _ ConfigurableAWSScanner = (*Scanner)(nil)
    34  
    35  type Scanner struct {
    36  	sync.Mutex
    37  	regoScanner           *rego.Scanner
    38  	debug                 debug.Logger
    39  	options               []options.ScannerOption
    40  	progressTracker       progress.Tracker
    41  	region                string
    42  	endpoint              string
    43  	services              []string
    44  	frameworks            []framework.Framework
    45  	spec                  string
    46  	concurrencyStrategy   concurrency.Strategy
    47  	policyDirs            []string
    48  	policyReaders         []io.Reader
    49  	policyFS              fs.FS
    50  	dataFs                fs.FS
    51  	loadEmbeddedPolicies  bool
    52  	loadEmbeddedLibraries bool
    53  	regoOnly              bool
    54  }
    55  
    56  func (s *Scanner) SetRegoOnly(value bool) {
    57  	s.regoOnly = value
    58  }
    59  
    60  func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {
    61  	s.frameworks = frameworks
    62  }
    63  
    64  func (s *Scanner) SetSpec(spec string) {
    65  	s.spec = spec
    66  }
    67  
    68  func (s *Scanner) Name() string {
    69  	return "AWS API"
    70  }
    71  
    72  func (s *Scanner) SetDebugWriter(writer io.Writer) {
    73  	s.debug = debug.New(writer, "aws-api", "scanner")
    74  }
    75  
    76  func (s *Scanner) SetProgressTracker(t progress.Tracker) {
    77  	s.progressTracker = t
    78  }
    79  
    80  func (s *Scanner) SetPolicyReaders(readers []io.Reader) {
    81  	s.policyReaders = readers
    82  }
    83  
    84  func (s *Scanner) SetPolicyDirs(dirs ...string) {
    85  	s.policyDirs = dirs
    86  }
    87  
    88  func (s *Scanner) SetPolicyFilesystem(fs fs.FS) {
    89  	s.policyFS = fs
    90  }
    91  
    92  func (s *Scanner) SetDataFilesystem(fs fs.FS) {
    93  	s.dataFs = fs
    94  }
    95  
    96  func (s *Scanner) SetUseEmbeddedPolicies(b bool) {
    97  	s.loadEmbeddedPolicies = b
    98  }
    99  
   100  func (s *Scanner) SetUseEmbeddedLibraries(b bool) {
   101  	s.loadEmbeddedLibraries = b
   102  }
   103  
   104  func (s *Scanner) SetTraceWriter(writer io.Writer)   {}
   105  func (s *Scanner) SetPerResultTracingEnabled(b bool) {}
   106  func (s *Scanner) SetDataDirs(s2 ...string)          {}
   107  func (s *Scanner) SetPolicyNamespaces(s2 ...string)  {}
   108  func (s *Scanner) SetSkipRequiredCheck(b bool)       {}
   109  func (s *Scanner) SetRegoErrorLimit(_ int)           {}
   110  
   111  func AllSupportedServices() []string {
   112  	return aws.AllServices()
   113  }
   114  
   115  func (s *Scanner) SetAWSRegion(region string) {
   116  	s.region = region
   117  }
   118  
   119  func (s *Scanner) SetAWSEndpoint(endpoint string) {
   120  	s.endpoint = endpoint
   121  }
   122  
   123  func (s *Scanner) SetAWSServices(services []string) {
   124  	s.services = services
   125  }
   126  
   127  func (s *Scanner) SetConcurrencyStrategy(strategy concurrency.Strategy) {
   128  	s.concurrencyStrategy = strategy
   129  }
   130  
   131  func New(opts ...options.ScannerOption) *Scanner {
   132  
   133  	s := &Scanner{
   134  		options:             opts,
   135  		progressTracker:     progress.NoProgress,
   136  		concurrencyStrategy: concurrency.DefaultStrategy,
   137  	}
   138  	for _, opt := range opts {
   139  		opt(s)
   140  	}
   141  	return s
   142  }
   143  
   144  func (s *Scanner) CreateState(ctx context.Context) (*state.State, error) {
   145  	cloudState, err := adapter.Adapt(ctx, cloudoptions.Options{
   146  		ProgressTracker:     s.progressTracker,
   147  		Region:              s.region,
   148  		Endpoint:            s.endpoint,
   149  		Services:            s.services,
   150  		DebugWriter:         s.debug,
   151  		ConcurrencyStrategy: s.concurrencyStrategy,
   152  	})
   153  	if err != nil {
   154  		var adaptionError errs.AdapterError
   155  		if errors.As(err, &adaptionError) {
   156  			s.debug.Log("There were %d errors during adaption process: %s", len(adaptionError.Errors()), adaptionError)
   157  		} else {
   158  			return nil, err
   159  		}
   160  	}
   161  	return cloudState, nil
   162  }
   163  
   164  func (s *Scanner) ScanWithStateRefresh(ctx context.Context) (results scan.Results, err error) {
   165  	cloudState, err := s.CreateState(ctx)
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  	return s.Scan(ctx, cloudState)
   170  }
   171  
   172  func (s *Scanner) Scan(ctx context.Context, cloudState *state.State) (results scan.Results, err error) {
   173  
   174  	if cloudState == nil {
   175  		return nil, fmt.Errorf("cloud state is nil")
   176  	}
   177  
   178  	// evaluate go rules
   179  	if !s.regoOnly {
   180  		for _, rule := range s.getRegisteredRules() {
   181  			select {
   182  			case <-ctx.Done():
   183  				return nil, ctx.Err()
   184  			default:
   185  			}
   186  			if rule.Rule().RegoPackage != "" {
   187  				continue
   188  			}
   189  			ruleResults := rule.Evaluate(cloudState)
   190  			if len(ruleResults) > 0 {
   191  				s.debug.Log("Found %d results for %s", len(ruleResults), rule.Rule().AVDID)
   192  				results = append(results, ruleResults...)
   193  			}
   194  		}
   195  	}
   196  
   197  	// evaluate rego rules
   198  	regoScanner, err := s.initRegoScanner()
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  	regoResults, err := regoScanner.ScanInput(ctx, rego.Input{
   203  		Contents: cloudState.ToRego(),
   204  	})
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  	return append(results, regoResults...), nil
   209  }
   210  
   211  func (s *Scanner) getRegisteredRules() []rules.RegisteredRule {
   212  	if len(s.frameworks) > 0 { // Only for maintaining backwards compat
   213  		return rules.GetFrameworkRules(s.frameworks...)
   214  	}
   215  	return rules.GetSpecRules(s.spec)
   216  }
   217  
   218  func (s *Scanner) initRegoScanner() (*rego.Scanner, error) {
   219  	s.Lock()
   220  	defer s.Unlock()
   221  	if s.regoScanner != nil {
   222  		return s.regoScanner, nil
   223  	}
   224  
   225  	srcFS := s.policyFS
   226  	if srcFS == nil {
   227  		if runtime.GOOS == "windows" {
   228  			homeDrive := os.Getenv("HOMEDRIVE")
   229  			if homeDrive == "" {
   230  				homeDrive = "C:"
   231  			}
   232  			srcFS = os.DirFS(homeDrive + "\\")
   233  		} else {
   234  			srcFS = os.DirFS("/")
   235  		}
   236  	}
   237  
   238  	regoScanner := rego.NewScanner(types.SourceCloud, s.options...)
   239  	regoScanner.SetParentDebugLogger(s.debug)
   240  	if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil {
   241  		return nil, err
   242  	}
   243  	s.regoScanner = regoScanner
   244  	return regoScanner, nil
   245  }