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

     1  package kubernetes
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  	"io/fs"
     7  	"path/filepath"
     8  	"sort"
     9  	"sync"
    10  
    11  	"github.com/khulnasoft-lab/defsec/pkg/types"
    12  
    13  	"github.com/khulnasoft-lab/defsec/pkg/framework"
    14  
    15  	"github.com/khulnasoft-lab/defsec/pkg/debug"
    16  
    17  	"github.com/khulnasoft-lab/defsec/pkg/scanners/options"
    18  
    19  	"github.com/liamg/memoryfs"
    20  
    21  	"github.com/khulnasoft-lab/defsec/pkg/rego"
    22  	"github.com/khulnasoft-lab/defsec/pkg/scanners/kubernetes/parser"
    23  
    24  	"github.com/khulnasoft-lab/defsec/pkg/scan"
    25  
    26  	"github.com/khulnasoft-lab/defsec/pkg/scanners"
    27  )
    28  
    29  var _ scanners.FSScanner = (*Scanner)(nil)
    30  var _ options.ConfigurableScanner = (*Scanner)(nil)
    31  
    32  type Scanner struct {
    33  	debug         debug.Logger
    34  	options       []options.ScannerOption
    35  	policyDirs    []string
    36  	policyReaders []io.Reader
    37  	regoScanner   *rego.Scanner
    38  	parser        *parser.Parser
    39  	skipRequired  bool
    40  	sync.Mutex
    41  	loadEmbeddedPolicies  bool
    42  	frameworks            []framework.Framework
    43  	spec                  string
    44  	loadEmbeddedLibraries bool
    45  }
    46  
    47  func (s *Scanner) SetSpec(spec string) {
    48  	s.spec = spec
    49  }
    50  
    51  func (s *Scanner) SetRegoOnly(bool) {}
    52  
    53  func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {
    54  	s.frameworks = frameworks
    55  }
    56  
    57  func (s *Scanner) SetUseEmbeddedPolicies(b bool) {
    58  	s.loadEmbeddedPolicies = b
    59  }
    60  
    61  func (s *Scanner) SetUseEmbeddedLibraries(b bool) {
    62  	s.loadEmbeddedLibraries = b
    63  }
    64  
    65  func (s *Scanner) SetPolicyReaders(readers []io.Reader) {
    66  	s.policyReaders = readers
    67  }
    68  
    69  func (s *Scanner) SetSkipRequiredCheck(skip bool) {
    70  	s.skipRequired = skip
    71  }
    72  
    73  func (s *Scanner) SetDebugWriter(writer io.Writer) {
    74  	s.debug = debug.New(writer, "kubernetes", "scanner")
    75  }
    76  
    77  func (s *Scanner) SetTraceWriter(_ io.Writer) {
    78  }
    79  
    80  func (s *Scanner) SetPerResultTracingEnabled(_ bool) {
    81  }
    82  
    83  func (s *Scanner) SetPolicyDirs(dirs ...string) {
    84  	s.policyDirs = dirs
    85  }
    86  
    87  func (s *Scanner) SetDataDirs(...string) {}
    88  func (s *Scanner) SetPolicyNamespaces(_ ...string) {
    89  }
    90  
    91  func (s *Scanner) SetPolicyFilesystem(_ fs.FS) {
    92  	// handled by rego when option is passed on
    93  }
    94  
    95  func (s *Scanner) SetDataFilesystem(_ fs.FS) {
    96  	// handled by rego when option is passed on
    97  }
    98  func (s *Scanner) SetRegoErrorLimit(_ int) {}
    99  
   100  func NewScanner(opts ...options.ScannerOption) *Scanner {
   101  	s := &Scanner{
   102  		options: opts,
   103  	}
   104  	for _, opt := range opts {
   105  		opt(s)
   106  	}
   107  	s.parser = parser.New(options.ParserWithSkipRequiredCheck(s.skipRequired))
   108  	return s
   109  }
   110  
   111  func (s *Scanner) Name() string {
   112  	return "Kubernetes"
   113  }
   114  
   115  func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) {
   116  	s.Lock()
   117  	defer s.Unlock()
   118  	if s.regoScanner != nil {
   119  		return s.regoScanner, nil
   120  	}
   121  	regoScanner := rego.NewScanner(types.SourceKubernetes, s.options...)
   122  	regoScanner.SetParentDebugLogger(s.debug)
   123  	if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil {
   124  		return nil, err
   125  	}
   126  	s.regoScanner = regoScanner
   127  	return regoScanner, nil
   128  }
   129  
   130  func (s *Scanner) ScanReader(ctx context.Context, filename string, reader io.Reader) (scan.Results, error) {
   131  	memfs := memoryfs.New()
   132  	if err := memfs.MkdirAll(filepath.Base(filename), 0o700); err != nil {
   133  		return nil, err
   134  	}
   135  	data, err := io.ReadAll(reader)
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  	if err := memfs.WriteFile(filename, data, 0o644); err != nil {
   140  		return nil, err
   141  	}
   142  	return s.ScanFS(ctx, memfs, ".")
   143  }
   144  
   145  func (s *Scanner) ScanFS(ctx context.Context, target fs.FS, dir string) (scan.Results, error) {
   146  
   147  	k8sFilesets, err := s.parser.ParseFS(ctx, target, dir)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  
   152  	if len(k8sFilesets) == 0 {
   153  		return nil, nil
   154  	}
   155  
   156  	var inputs []rego.Input
   157  	for path, k8sFiles := range k8sFilesets {
   158  		for _, content := range k8sFiles {
   159  			inputs = append(inputs, rego.Input{
   160  				Path:     path,
   161  				FS:       target,
   162  				Contents: content,
   163  			})
   164  		}
   165  	}
   166  
   167  	regoScanner, err := s.initRegoScanner(target)
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  
   172  	s.debug.Log("Scanning %d files...", len(inputs))
   173  	results, err := regoScanner.ScanInput(ctx, inputs...)
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  	results.SetSourceAndFilesystem("", target, false)
   178  
   179  	sort.Slice(results, func(i, j int) bool {
   180   		return results[i].Rule().AVDID < results[j].Rule().AVDID
   181   	})
   182  	return results, nil
   183  }