Skip to content

Commit

Permalink
Adds support to scan config resources with applicable policies & Refa…
Browse files Browse the repository at this point in the history
…ctors filteration (#803)

* implement regometada filters

* tests

* Policy type filter added (#29)

* policy type filter added

* variable name issue fixed
1. cloud type --> policytypes

* more unit tests

* fix validation

* adds header to new files

* incorporate review comments

Co-authored-by: Gaurav Gogia <16029099+gaurav-gogia@users.noreply.github.com>
  • Loading branch information
patilpankaj212 and gaurav-gogia committed Jun 3, 2021
1 parent 9adfe1d commit 5f4b15a
Show file tree
Hide file tree
Showing 13 changed files with 856 additions and 701 deletions.
131 changes: 131 additions & 0 deletions pkg/filters/filter-specs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
Copyright (C) 2020 Accurics, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package filters

import (
"github.com/accurics/terrascan/pkg/policy"
"github.com/accurics/terrascan/pkg/utils"
)

// PolicyTypesFilterSpecification is policy type based Filter Spec
type PolicyTypesFilterSpecification struct {
policyTypes []string
}

// IsSatisfied implementation for policy type based Filter spec
func (p PolicyTypesFilterSpecification) IsSatisfied(r *policy.RegoMetadata) bool {
// if policy type is not present for rego metadata,
// or if policy types is not specified, return true
if len(r.PolicyType) < 1 || len(p.policyTypes) < 1 {
return true
}
return utils.CheckPolicyType(r.PolicyType, p.policyTypes)
}

// ResourceTypeFilterSpecification is resource type based Filter Spec
type ResourceTypeFilterSpecification struct {
resourceType string
}

// IsSatisfied implementation for resource type based Filter spec
func (rs ResourceTypeFilterSpecification) IsSatisfied(r *policy.RegoMetadata) bool {
// if resource type is not present for rego metadata, return true
if len(r.ResourceType) < 1 {
return true
}
return rs.resourceType == r.ResourceType
}

// RerefenceIDFilterSpecification is reference ID based Filter Spec
type RerefenceIDFilterSpecification struct {
ReferenceID string
}

// IsSatisfied implementation for reference ID based Filter spec
func (rs RerefenceIDFilterSpecification) IsSatisfied(r *policy.RegoMetadata) bool {
return rs.ReferenceID == r.ReferenceID
}

// RerefenceIDsFilterSpecification is reference IDs based Filter Spec
type RerefenceIDsFilterSpecification struct {
ReferenceIDs []string
}

// IsSatisfied implementation for reference IDs based Filter spec
func (rs RerefenceIDsFilterSpecification) IsSatisfied(r *policy.RegoMetadata) bool {
// when reference ID's are not specified (could be skip or scan rules),
// return true
if len(rs.ReferenceIDs) < 1 {
return true
}
isSatisfied := false
for _, refID := range rs.ReferenceIDs {
rfIDSpec := RerefenceIDFilterSpecification{refID}
if rfIDSpec.IsSatisfied(r) {
isSatisfied = true
break
}
}
return isSatisfied
}

// CategoryFilterSpecification is categories based Filter Spec
type CategoryFilterSpecification struct {
categories []string
}

// IsSatisfied implementation for category based Filter spec
func (c CategoryFilterSpecification) IsSatisfied(r *policy.RegoMetadata) bool {
// when categories are not specified, return true
if len(c.categories) < 1 {
return true
}
return utils.CheckCategory(r.Category, c.categories)
}

// SeverityFilterSpecification is severity based Filter Spec
type SeverityFilterSpecification struct {
severity string
}

// IsSatisfied implementation for severity based Filter spec
func (s SeverityFilterSpecification) IsSatisfied(r *policy.RegoMetadata) bool {
// when severity is not specified, return true
if len(s.severity) < 1 {
return true
}
return utils.CheckSeverity(r.Severity, s.severity)
}

// AndFilterSpecification is a logical AND Filter spec which
// determines if a list of filter specs satisfy the condition
type AndFilterSpecification struct {
filterSpecs []policy.FilterSpecification
}

// IsSatisfied implementation for And Filter spec
func (a AndFilterSpecification) IsSatisfied(r *policy.RegoMetadata) bool {
if len(a.filterSpecs) < 1 {
return false
}
for _, filterSpec := range a.filterSpecs {
if !filterSpec.IsSatisfied(r) {
return false
}
}
return true
}
88 changes: 88 additions & 0 deletions pkg/filters/filters.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
Copyright (C) 2020 Accurics, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package filters

import (
"github.com/accurics/terrascan/pkg/policy"
)

// RegoMetadataPreLoadFilter is a pre load filter
// this filter would be while the policy files are processed by policy engine
type RegoMetadataPreLoadFilter struct {
scanRules []string
skipRules []string
categories []string
policyTypes []string
severity string
filterSpecs []policy.FilterSpecification
}

// NewRegoMetadataPreLoadFilter is a constructor func for RegoMetadataPreLoadFilter
func NewRegoMetadataPreLoadFilter(scanRules, skipRules, categories, policyTypes []string, severity string) *RegoMetadataPreLoadFilter {
return &RegoMetadataPreLoadFilter{
scanRules: scanRules,
skipRules: skipRules,
categories: categories,
policyTypes: policyTypes,
severity: severity,
// add applicable filter specs to the list
filterSpecs: []policy.FilterSpecification{
RerefenceIDsFilterSpecification{scanRules},
CategoryFilterSpecification{categories: categories},
SeverityFilterSpecification{severity: severity},
PolicyTypesFilterSpecification{policyTypes: policyTypes},
},
}
}

// IsFiltered checks whether a RegoMetada should be filtered or not
func (r *RegoMetadataPreLoadFilter) IsFiltered(regoMetadata *policy.RegoMetadata) bool {
// if skip rules are specified, RegoMetada is not filtered
if len(r.skipRules) < 1 {
return false
}
refIDsSpec := RerefenceIDsFilterSpecification{r.skipRules}
return refIDsSpec.IsSatisfied(regoMetadata)
}

// IsAllowed checks whether a RegoMetada should be allowed or not
func (r *RegoMetadataPreLoadFilter) IsAllowed(regoMetadata *policy.RegoMetadata) bool {
andSpec := AndFilterSpecification{r.filterSpecs}
return andSpec.IsSatisfied(regoMetadata)
}

// RegoDataFilter is a pre scan filter,
// it will be used by policy engine before the evaluation of resources start
type RegoDataFilter struct{}

// Filter func will filter based on resource type
func (r *RegoDataFilter) Filter(rmap map[string]*policy.RegoData, input policy.EngineInput) map[string]*policy.RegoData {
// if resource config is empty, return original map
if len(*input.InputData) < 1 {
return rmap
}
tempMap := make(map[string]*policy.RegoData)
for resType := range *input.InputData {
for k := range rmap {
resFilterSpec := ResourceTypeFilterSpecification{resType}
if resFilterSpec.IsSatisfied(&rmap[k].Metadata) {
tempMap[k] = rmap[k]
}
}
}
return tempMap
}

0 comments on commit 5f4b15a

Please sign in to comment.