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

     1  package arm
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"io/fs"
     8  	"sync"
     9  
    10  	"github.com/khulnasoft-lab/defsec/internal/adapters/arm"
    11  	"github.com/khulnasoft-lab/defsec/pkg/rego"
    12  	"github.com/khulnasoft-lab/defsec/pkg/rules"
    13  	"github.com/khulnasoft-lab/defsec/pkg/scanners/azure"
    14  	"github.com/khulnasoft-lab/defsec/pkg/state"
    15  	"github.com/khulnasoft-lab/defsec/pkg/types"
    16  
    17  	"github.com/khulnasoft-lab/defsec/pkg/debug"
    18  
    19  	"github.com/khulnasoft-lab/defsec/pkg/scan"
    20  
    21  	"github.com/khulnasoft-lab/defsec/pkg/framework"
    22  	"github.com/khulnasoft-lab/defsec/pkg/scanners"
    23  	"github.com/khulnasoft-lab/defsec/pkg/scanners/azure/arm/parser"
    24  	"github.com/khulnasoft-lab/defsec/pkg/scanners/options"
    25  )
    26  
    27  var _ scanners.FSScanner = (*Scanner)(nil)
    28  var _ options.ConfigurableScanner = (*Scanner)(nil)
    29  
    30  type Scanner struct {
    31  	scannerOptions        []options.ScannerOption
    32  	parserOptions         []options.ParserOption
    33  	debug                 debug.Logger
    34  	frameworks            []framework.Framework
    35  	skipRequired          bool
    36  	regoOnly              bool
    37  	loadEmbeddedPolicies  bool
    38  	loadEmbeddedLibraries bool
    39  	policyDirs            []string
    40  	policyReaders         []io.Reader
    41  	regoScanner           *rego.Scanner
    42  	spec                  string
    43  	sync.Mutex
    44  }
    45  
    46  func (s *Scanner) SetSpec(spec string) {
    47  	s.spec = spec
    48  }
    49  
    50  func (s *Scanner) SetRegoOnly(regoOnly bool) {
    51  	s.regoOnly = regoOnly
    52  }
    53  
    54  func New(opts ...options.ScannerOption) *Scanner {
    55  	scanner := &Scanner{
    56  		scannerOptions: opts,
    57  	}
    58  	for _, opt := range opts {
    59  		opt(scanner)
    60  	}
    61  	return scanner
    62  }
    63  
    64  func (s *Scanner) Name() string {
    65  	return "Azure ARM"
    66  }
    67  
    68  func (s *Scanner) SetDebugWriter(writer io.Writer) {
    69  	s.debug = debug.New(writer, "azure", "arm")
    70  	s.parserOptions = append(s.parserOptions, options.ParserWithDebug(writer))
    71  }
    72  
    73  func (s *Scanner) SetPolicyDirs(dirs ...string) {
    74  	s.policyDirs = dirs
    75  }
    76  
    77  func (s *Scanner) SetSkipRequiredCheck(skipRequired bool) {
    78  	s.skipRequired = skipRequired
    79  }
    80  func (s *Scanner) SetPolicyReaders(readers []io.Reader) {
    81  	s.policyReaders = readers
    82  }
    83  
    84  func (s *Scanner) SetPolicyFilesystem(_ fs.FS) {
    85  	// handled by rego when option is passed on
    86  }
    87  func (s *Scanner) SetDataFilesystem(_ fs.FS) {
    88  	// handled by rego when option is passed on
    89  }
    90  
    91  func (s *Scanner) SetUseEmbeddedPolicies(b bool) {
    92  	s.loadEmbeddedPolicies = b
    93  }
    94  
    95  func (s *Scanner) SetUseEmbeddedLibraries(b bool) {
    96  	s.loadEmbeddedLibraries = b
    97  }
    98  
    99  func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {
   100  	s.frameworks = frameworks
   101  }
   102  
   103  func (s *Scanner) SetTraceWriter(io.Writer)        {}
   104  func (s *Scanner) SetPerResultTracingEnabled(bool) {}
   105  func (s *Scanner) SetDataDirs(...string)           {}
   106  func (s *Scanner) SetPolicyNamespaces(...string)   {}
   107  func (s *Scanner) SetRegoErrorLimit(_ int)         {}
   108  
   109  func (s *Scanner) initRegoScanner(srcFS fs.FS) error {
   110  	s.Lock()
   111  	defer s.Unlock()
   112  	if s.regoScanner != nil {
   113  		return nil
   114  	}
   115  	regoScanner := rego.NewScanner(types.SourceCloud, s.scannerOptions...)
   116  	regoScanner.SetParentDebugLogger(s.debug)
   117  	if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil {
   118  		return err
   119  	}
   120  	s.regoScanner = regoScanner
   121  	return nil
   122  }
   123  
   124  func (s *Scanner) ScanFS(ctx context.Context, fs fs.FS, dir string) (scan.Results, error) {
   125  	p := parser.New(fs, s.parserOptions...)
   126  	deployments, err := p.ParseFS(ctx, dir)
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  	if err := s.initRegoScanner(fs); err != nil {
   131  		return nil, err
   132  	}
   133  
   134  	return s.scanDeployments(ctx, deployments, fs)
   135  }
   136  
   137  func (s *Scanner) scanDeployments(ctx context.Context, deployments []azure.Deployment, f fs.FS) (scan.Results, error) {
   138  
   139  	var results scan.Results
   140  
   141  	for _, deployment := range deployments {
   142  
   143  		result, err := s.scanDeployment(ctx, deployment, f)
   144  		if err != nil {
   145  			return nil, err
   146  		}
   147  		results = append(results, result...)
   148  	}
   149  
   150  	return results, nil
   151  }
   152  
   153  func (s *Scanner) scanDeployment(ctx context.Context, deployment azure.Deployment, fs fs.FS) (scan.Results, error) {
   154  	var results scan.Results
   155  	deploymentState := s.adaptDeployment(ctx, deployment)
   156  	if !s.regoOnly {
   157  		for _, rule := range rules.GetRegistered(s.frameworks...) {
   158  			select {
   159  			case <-ctx.Done():
   160  				return nil, ctx.Err()
   161  			default:
   162  			}
   163  			if rule.Rule().RegoPackage != "" {
   164  				continue
   165  			}
   166  			ruleResults := rule.Evaluate(deploymentState)
   167  			s.debug.Log("Found %d results for %s", len(ruleResults), rule.Rule().AVDID)
   168  			if len(ruleResults) > 0 {
   169  				results = append(results, ruleResults...)
   170  			}
   171  		}
   172  	}
   173  
   174  	regoResults, err := s.regoScanner.ScanInput(ctx, rego.Input{
   175  		Path:     deployment.Metadata.Range().GetFilename(),
   176  		FS:       fs,
   177  		Contents: deploymentState.ToRego(),
   178  	})
   179  	if err != nil {
   180  		return nil, fmt.Errorf("rego scan error: %w", err)
   181  	}
   182  
   183  	return append(results, regoResults...), nil
   184  }
   185  
   186  func (s *Scanner) adaptDeployment(ctx context.Context, deployment azure.Deployment) *state.State {
   187  	return arm.Adapt(ctx, deployment)
   188  }