Skip to content

Commit

Permalink
feat: add deployment placeholder function
Browse files Browse the repository at this point in the history
Signed-off-by: Owen Rumney <[email protected]>
  • Loading branch information
Owen Rumney committed Oct 12, 2022
1 parent a04cb87 commit 9a2d763
Show file tree
Hide file tree
Showing 3 changed files with 209 additions and 37 deletions.
105 changes: 77 additions & 28 deletions pkg/scanners/azure/arm/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ package arm

import (
"context"
"fmt"
"io"
"io/fs"
"sync"

"github.com/aquasecurity/defsec/internal/adapters/arm"
"github.com/aquasecurity/defsec/pkg/rego"
"github.com/aquasecurity/defsec/pkg/rules"
"github.com/aquasecurity/defsec/pkg/scanners/azure"
"github.com/aquasecurity/defsec/pkg/state"
"github.com/aquasecurity/defsec/pkg/types"

"github.com/aquasecurity/defsec/pkg/debug"

Expand All @@ -28,6 +32,13 @@ type Scanner struct {
parserOptions []options.ParserOption
debug debug.Logger
frameworks []framework.Framework
skipRequired bool
regoOnly bool
loadEmbedded bool
policyDirs []string
policyReaders []io.Reader
regoScanner *rego.Scanner
sync.Mutex
}

func New(opts ...options.ScannerOption) *Scanner {
Expand All @@ -44,58 +55,87 @@ func (s *Scanner) Name() string {
return "Azure ARM"
}

func (s *Scanner) ScanFS(ctx context.Context, fs fs.FS, dir string) (scan.Results, error) {
p := parser.New(fs, s.parserOptions...)
deployments, err := p.ParseFS(ctx, dir)
if err != nil {
return nil, err
}
return s.scanDeployments(ctx, deployments)
}

func (s *Scanner) SetDebugWriter(writer io.Writer) {
s.debug = debug.New(writer, "azure", "arm")
s.parserOptions = append(s.parserOptions, options.ParserWithDebug(writer))
}

func (s *Scanner) SetTraceWriter(writer io.Writer) {
func (s *Scanner) SetPolicyDirs(dirs ...string) {
s.policyDirs = dirs
}

func (s *Scanner) SetPerResultTracingEnabled(b bool) {
func (s *Scanner) SetSkipRequiredCheck(skipRequired bool) {
s.skipRequired = skipRequired
}

func (s *Scanner) SetPolicyDirs(s2 ...string) {
func (s *Scanner) SetPolicyReaders(readers []io.Reader) {
s.policyReaders = readers
}

func (s *Scanner) SetDataDirs(s2 ...string) {
func (s *Scanner) SetPolicyFilesystem(_ fs.FS) {
// handled by rego when option is passed on
}

func (s *Scanner) SetPolicyNamespaces(s2 ...string) {
func (s *Scanner) SetUseEmbeddedPolicies(loadEmbedded bool) {
s.loadEmbedded = loadEmbedded
}

func (s *Scanner) SetSkipRequiredCheck(b bool) {
func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {
s.frameworks = frameworks
}

func (s *Scanner) SetPolicyReaders(readers []io.Reader) {
}
func (s *Scanner) SetTraceWriter(io.Writer) {}
func (s *Scanner) SetPerResultTracingEnabled(bool) {}
func (s *Scanner) SetDataDirs(...string) {}
func (s *Scanner) SetPolicyNamespaces(...string) {}

func (s *Scanner) SetPolicyFilesystem(fs fs.FS) {
func (s *Scanner) initRegoScanner(srcFS fs.FS) error {
s.Lock()
defer s.Unlock()
if s.regoScanner != nil {
return nil
}
regoScanner := rego.NewScanner(types.SourceCloud, s.scannerOptions...)
regoScanner.SetParentDebugLogger(s.debug)
if err := regoScanner.LoadPolicies(s.loadEmbedded, srcFS, s.policyDirs, s.policyReaders); err != nil {
return err
}
s.regoScanner = regoScanner
return nil
}

func (s *Scanner) SetUseEmbeddedPolicies(b bool) {
}
func (s *Scanner) ScanFS(ctx context.Context, fs fs.FS, dir string) (scan.Results, error) {
p := parser.New(fs, s.parserOptions...)
deployments, err := p.ParseFS(ctx, dir)
if err != nil {
return nil, err
}
if err := s.initRegoScanner(fs); err != nil {
return nil, err
}

func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {
s.frameworks = frameworks
return s.scanDeployments(ctx, deployments, fs)
}

func (s *Scanner) scanDeployments(ctx context.Context, deployments []azure.Deployment) (scan.Results, error) {
func (s *Scanner) scanDeployments(ctx context.Context, deployments []azure.Deployment, f fs.FS) (scan.Results, error) {

var results scan.Results

for _, deployment := range deployments {
// TODO: adapt each deployment into a state
cloudState := s.adaptDeployment(ctx, deployment)

result, err := s.scanDeployment(ctx, deployment, f)
if err != nil {
return nil, err
}
results = append(results, result...)
}

return results, nil
}

func (s *Scanner) scanDeployment(ctx context.Context, deployment azure.Deployment, fs fs.FS) (scan.Results, error) {
var results scan.Results
deploymentState := s.adaptDeployment(ctx, deployment)
if !s.regoOnly {
for _, rule := range rules.GetRegistered(s.frameworks...) {
select {
case <-ctx.Done():
Expand All @@ -105,15 +145,24 @@ func (s *Scanner) scanDeployments(ctx context.Context, deployments []azure.Deplo
if rule.Rule().RegoPackage != "" {
continue
}
ruleResults := rule.Evaluate(cloudState)
ruleResults := rule.Evaluate(deploymentState)
s.debug.Log("Found %d results for %s", len(ruleResults), rule.Rule().AVDID)
if len(ruleResults) > 0 {
results = append(results, ruleResults...)
}
}
}

return results, nil
regoResults, err := s.regoScanner.ScanInput(ctx, rego.Input{
Path: deployment.Metadata.Range().GetFilename(),
FS: fs,
Contents: deploymentState.ToRego(),
})
if err != nil {
return nil, fmt.Errorf("rego scan error: %w", err)
}

return append(results, regoResults...), nil
}

func (s *Scanner) adaptDeployment(ctx context.Context, deployment azure.Deployment) *state.State {
Expand Down
88 changes: 84 additions & 4 deletions pkg/scanners/azure/deployment.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package azure

import (
"os"

"github.com/aquasecurity/defsec/pkg/types"
)

Expand Down Expand Up @@ -52,10 +54,7 @@ type Decorator struct {
type Scope string

const (
ScopeResourceGroup Scope = "resourceGroup"
ScopeSubscription Scope = "subscription"
ScopeTenant Scope = "tenant"
ScopeManagementGroup Scope = "managementGroup"
ScopeResourceGroup Scope = "resourceGroup"
)

func (d *Deployment) GetResourcesByType(t string) []Resource {
Expand Down Expand Up @@ -97,3 +96,84 @@ func (d *Deployment) GetVariable(variableName string) interface{} {
}
return nil
}

func (d *Deployment) GetEnvVariable(envVariableName string) interface{} {

if envVariable, exists := os.LookupEnv(envVariableName); exists {
return envVariable
}
return nil
}

func (d *Deployment) GetOutput(outputName string) interface{} {

for _, output := range d.Outputs {
if output.Name == outputName {
return output.Value.Raw()
}
}
return nil
}

func (d *Deployment) GetDeployment() interface{} {

type template struct {
Schema string `json:"$schema"`
ContentVersion string `json:"contentVersion"`
Parameters map[string]interface{} `json:"parameters"`
Variables map[string]interface{} `json:"variables"`
Resources []interface{} `json:"resources"`
Outputs map[string]interface{} `json:"outputs"`
}

type templateLink struct {
URI string `json:"uri"`
}

type properties struct {
TemplateLink templateLink `json:"templateLink"`
Template template `json:"template"`
TemplateHash string `json:"templateHash"`
Parameters map[string]interface{} `json:"parameters"`
Mode string `json:"mode"`
ProvisioningState string `json:"provisioningState"`
}

deploymentShell := struct {
Name string `json:"name"`
Properties properties `json:"properties"`
}{
Name: "Placeholder Deployment",
Properties: properties{
TemplateLink: templateLink{
URI: "https://placeholder.com",
},
Template: template{
Schema: "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
ContentVersion: "",
Parameters: make(map[string]interface{}),
Variables: make(map[string]interface{}),
Resources: make([]interface{}, 0),
Outputs: make(map[string]interface{}),
},
},
}

for _, parameter := range d.Parameters {
deploymentShell.Properties.Template.Parameters[parameter.Name] = parameter.Value.Raw()
}

for _, variable := range d.Variables {
deploymentShell.Properties.Template.Variables[variable.Name] = variable.Value.Raw()
}

for _, resource := range d.Resources {
deploymentShell.Properties.Template.Resources = append(deploymentShell.Properties.Template.Resources, resource)
}

for _, output := range d.Outputs {
deploymentShell.Properties.Template.Outputs[output.Name] = output.Value.Raw()
}

return deploymentShell
}
53 changes: 48 additions & 5 deletions pkg/scanners/azure/functions/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,61 @@ package functions
type DeploymentData interface {
GetParameter(name string) interface{}
GetVariable(variableName string) interface{}
GetEnvVariable(envVariableName string) interface{}
}

func Deployment(deploymentProvider DeploymentData, args ...interface{}) interface{} {
panic("not implemented")

/*
{
"name": "",
"properties": {
"templateLink": {
"uri": ""
},
"template": {
"$schema": "",
"contentVersion": "",
"parameters": {},
"variables": {},
"resources": [],
"outputs": {}
},
"templateHash": "",
"parameters": {},
"mode": "",
"provisioningState": ""
}
}
*/

return nil
}

func Environment(deploymentProvider DeploymentData, args ...interface{}) interface{} {
panic("not implemented")
func Environment(envProvider DeploymentData, args ...interface{}) interface{} {
if len(args) == 0 {
return nil
}

envVarName, ok := args[0].(string)
if !ok {
return nil
}
return envProvider.GetEnvVariable(envVarName)
}

func Variables(deploymentProvider DeploymentData, args ...interface{}) interface{} {
panic("not implemented")
func Variables(varProvider DeploymentData, args ...interface{}) interface{} {
if len(args) == 0 {
return nil
}

varName, ok := args[0].(string)
if !ok {
return nil
}
return varProvider.GetVariable(varName)
}

func Parameters(paramProvider DeploymentData, args ...interface{}) interface{} {
Expand Down

0 comments on commit 9a2d763

Please sign in to comment.