Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds support to scan config resources with applicable policies & Refactors filteration #803

Merged
merged 7 commits into from
Jun 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
Loading