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 }