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