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 }