Skip to content

Commit

Permalink
Adds: in-file instrumentation for resource prioritizing (tenable#802)
Browse files Browse the repository at this point in the history
* Adds: support for in-file instrumentation for prioritising and de-prioritising terraform and k8s resources.
  • Loading branch information
Rchanger authored May 28, 2021
1 parent afc2a18 commit 5057073
Show file tree
Hide file tree
Showing 36 changed files with 1,082 additions and 55 deletions.
33 changes: 31 additions & 2 deletions pkg/iac-providers/kubernetes/v1/normalize.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,19 @@ import (
)

const (
terrascanSkip = "terrascanSkip"
terrascanSkip = "runterrascan.io/skip"
terrascanSkipRule = "rule"
terrascanSkipComment = "comment"
terrascanMaxSeverity = "runterrascan.io/maxseverity"
terrascanMinSeverity = "runterrascan.io/minseverity"
)

var (
errUnsupportedDoc = fmt.Errorf("unsupported document type")
// ErrNoKind is returned when the "kind" key is not available (not a valid kubernetes resource)
ErrNoKind = fmt.Errorf("kind does not exist")

infileInstructionNotPresentLog = "%s not present for resource: %s"
)

// k8sMetadata is used to pull the name, namespace types and annotations for a given resource
Expand Down Expand Up @@ -139,6 +143,11 @@ func (k *K8sV1) Normalize(doc *utils.IacDocument) (*output.ResourceConfig, error
resourceConfig.SkipRules = append(resourceConfig.SkipRules, skipRules...)
}

maxSeverity, minSeverity := readMinMaxSeverityFromAnnotations(resource.Metadata.Annotations, resourceConfig.ID)

resourceConfig.MaxSeverity = maxSeverity
resourceConfig.MinSeverity = minSeverity

configData := make(map[string]interface{})
if err = json.Unmarshal(*jsonData, &configData); err != nil {
return nil, err
Expand All @@ -155,7 +164,7 @@ func readSkipRulesFromAnnotations(annotations map[string]interface{}, resourceID
var skipRulesFromAnnotations interface{}
var ok bool
if skipRulesFromAnnotations, ok = annotations[terrascanSkip]; !ok {
zap.S().Debugf("%s not present for resource: %s", terrascanSkip, resourceID)
zap.S().Debugf(infileInstructionNotPresentLog, terrascanSkip, resourceID)
return nil
}

Expand All @@ -172,3 +181,23 @@ func readSkipRulesFromAnnotations(annotations map[string]interface{}, resourceID
zap.S().Debugf("%s must be a string containing an json array like [{rule: ruleID, comment: reason for skipping}]", terrascanSkip)
return nil
}

// readMinMaxSeverityFromAnnotations finds the min max severity values set in annotations for the resource
func readMinMaxSeverityFromAnnotations(annotations map[string]interface{}, resourceID string) (maxSeverity, minSeverity string) {
var (
minSeverityAnnotation interface{}
maxSeverityAnnotation interface{}
ok bool
)
if minSeverityAnnotation, ok = annotations[terrascanMinSeverity]; !ok {
zap.S().Debugf(infileInstructionNotPresentLog, terrascanMinSeverity, resourceID)
} else if minSeverity, ok = minSeverityAnnotation.(string); !ok {
zap.S().Debugf("%s must be a string cantaining value as (High | Low| Medium)", terrascanMinSeverity)
}
if maxSeverityAnnotation, ok = annotations[terrascanMaxSeverity]; !ok {
zap.S().Debugf(infileInstructionNotPresentLog, terrascanMaxSeverity, resourceID)
} else if maxSeverity, ok = maxSeverityAnnotation.(string); !ok {
zap.S().Debugf("%s must be a string cantaining value as (High | Low| Medium)", terrascanMaxSeverity)
}
return
}
80 changes: 78 additions & 2 deletions pkg/iac-providers/kubernetes/v1/normalize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ kind: Pod
metadata:
name: myapp-pod
annotations:
terrascanSkip: |
runterrascan.io/skip: |
[{"rule": "accurics.kubernetes.IAM.109", "comment": "reason to skip the rule"}]
spec:
containers:
Expand All @@ -68,7 +68,7 @@ kind: CRD
metadata:
generateName: myapp-pod-prefix-
annotations:
terrascanSkip: |
runterrascan.io/skip: |
[{"rule": "accurics.kubernetes.IAM.109", "comment": "reason to skip the rule"}]
spec:
containers:
Expand Down Expand Up @@ -413,3 +413,79 @@ func TestReadSkipRulesFromAnnotations(t *testing.T) {
})
}
}

func TestReadMinMaxSeverityFromAnnotations(t *testing.T) {
type args struct {
annotations map[string]interface{}
resourceID string
}
tests := []struct {
name string
args args
wantMaxSeverity string
wantMinSeverity string
}{
{
name: "no severity",
args: args{
annotations: map[string]interface{}{
"test": "test",
},
},
wantMinSeverity: "",
wantMaxSeverity: "",
},
{
name: "min severity set to high",
args: args{annotations: map[string]interface{}{
terrascanMinSeverity: "High",
}},
wantMinSeverity: "High",
wantMaxSeverity: "",
},
{
name: "max severity set to low",
args: args{annotations: map[string]interface{}{
terrascanMaxSeverity: "Low",
}},
wantMinSeverity: "",
wantMaxSeverity: "Low",
},
{
name: "max severity set to None",
args: args{annotations: map[string]interface{}{
terrascanMaxSeverity: "None"}},
wantMinSeverity: "",
wantMaxSeverity: "None",
},
{
name: "max severity set to low and Min severity set to high",
args: args{annotations: map[string]interface{}{
terrascanMaxSeverity: "LOw",
terrascanMinSeverity: "hiGh",
}},
wantMinSeverity: "hiGh",
wantMaxSeverity: "LOw",
},
{
name: "invalid min and max value",
args: args{annotations: map[string]interface{}{
terrascanMaxSeverity: 2,
terrascanMinSeverity: false,
}},
wantMinSeverity: "",
wantMaxSeverity: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotMaxSeverity, gotMinSeverity := readMinMaxSeverityFromAnnotations(tt.args.annotations, tt.args.resourceID)
if gotMaxSeverity != tt.wantMaxSeverity {
t.Errorf("readMinMaxSeverityFromAnnotations() gotMaxSeverity = %v, want %v", gotMaxSeverity, tt.wantMaxSeverity)
}
if gotMinSeverity != tt.wantMinSeverity {
t.Errorf("readMinMaxSeverityFromAnnotations() gotMinSeverity = %v, want %v", gotMinSeverity, tt.wantMinSeverity)
}
})
}
}
4 changes: 3 additions & 1 deletion pkg/iac-providers/output/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ type ResourceConfig struct {
// SkipRules will hold the rules to be skipped for the resource.
// Each iac provider should append the rules to be skipped for a resource,
// while extracting resource from the iac files
SkipRules []SkipRule `json:"skip_rules" yaml:"skip_rules"`
SkipRules []SkipRule `json:"skip_rules" yaml:"skip_rules"`
MaxSeverity string `json:"max_severity"`
MinSeverity string `json:"min_severity"`
}

// SkipRule struct will hold the skipped rule and any comment for the skipped rule
Expand Down
17 changes: 10 additions & 7 deletions pkg/iac-providers/terraform/commons/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,18 @@ func CreateResourceConfig(managedResource *hclConfigs.Resource) (resourceConfig
return resourceConfig, fmt.Errorf("failed to convert hcl.Body to go struct")
}

minSeverity, maxSeverity := utils.GetMinMaxSeverity(c.rangeSource(hclBody.Range()))
// create a resource config
resourceConfig = output.ResourceConfig{
ID: fmt.Sprintf("%s.%s", managedResource.Type, managedResource.Name),
Name: managedResource.Name,
Type: managedResource.Type,
Source: managedResource.DeclRange.Filename,
Line: managedResource.DeclRange.Start.Line,
Config: goOut,
SkipRules: utils.GetSkipRules(c.rangeSource(hclBody.Range())),
ID: fmt.Sprintf("%s.%s", managedResource.Type, managedResource.Name),
Name: managedResource.Name,
Type: managedResource.Type,
Source: managedResource.DeclRange.Filename,
Line: managedResource.DeclRange.Start.Line,
Config: goOut,
SkipRules: utils.GetSkipRules(c.rangeSource(hclBody.Range())),
MaxSeverity: maxSeverity,
MinSeverity: minSeverity,
}

// successful
Expand Down
32 changes: 24 additions & 8 deletions pkg/iac-providers/terraform/v12/testdata/tfjson/config1.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@
"${aws_security_group.sg_playground.id}"
]
},
"skip_rules": null
"skip_rules": null,
"max_severity": "",
"min_severity": ""
}
],
"aws_internet_gateway": [
Expand All @@ -57,7 +59,9 @@
},
"vpc_id": "${aws_vpc.vpc_playground.id}"
},
"skip_rules": null
"skip_rules": null,
"max_severity": "",
"min_severity": ""
}
],
"aws_key_pair": [
Expand All @@ -72,7 +76,9 @@
"key_name": "testKey",
"public_key": "${file(var.public_key_path)}"
},
"skip_rules": null
"skip_rules": null,
"max_severity": "",
"min_severity": ""
}
],
"aws_route_table": [
Expand All @@ -95,7 +101,9 @@
},
"vpc_id": "${aws_vpc.vpc_playground.id}"
},
"skip_rules": null
"skip_rules": null,
"max_severity": "",
"min_severity": ""
}
],
"aws_route_table_association": [
Expand All @@ -110,7 +118,9 @@
"route_table_id": "${aws_route_table.rtb_public_playground.id}",
"subnet_id": "${aws_subnet.subnet_public_playground.id}"
},
"skip_rules": null
"skip_rules": null,
"max_severity": "",
"min_severity": ""
}
],
"aws_security_group": [
Expand Down Expand Up @@ -156,7 +166,9 @@
},
"vpc_id": "${aws_vpc.vpc_playground.id}"
},
"skip_rules": null
"skip_rules": null,
"max_severity": "",
"min_severity": ""
}
],
"aws_subnet": [
Expand All @@ -175,7 +187,9 @@
},
"vpc_id": "${aws_vpc.vpc_playground.id}"
},
"skip_rules": null
"skip_rules": null,
"max_severity": "",
"min_severity": ""
}
],
"aws_vpc": [
Expand All @@ -194,7 +208,9 @@
"Environment": "${var.environment_tag}"
}
},
"skip_rules": null
"skip_rules": null,
"max_severity": "",
"min_severity": ""
}
]
}
16 changes: 12 additions & 4 deletions pkg/iac-providers/terraform/v12/testdata/tfjson/dummyconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
"region": "${var.region}"
}
},
"skip_rules": null
"skip_rules": null,
"max_severity": "",
"min_severity": ""
}
],
"type1": [
Expand All @@ -43,7 +45,9 @@
"test2": 5,
"test3": "${1 + 2}"
},
"skip_rules": null
"skip_rules": null,
"max_severity": "",
"min_severity": ""
}
],
"type2": [
Expand All @@ -66,7 +70,9 @@
"thing": "${[for x in local.arr: x * 2]}"
}
},
"skip_rules": null
"skip_rules": null,
"max_severity": "",
"min_severity": ""
}
],
"type3": [
Expand All @@ -83,7 +89,9 @@
"heredoc2": "\t\tAnother heredoc, that\n\t\tdoesn't remove indentation\n\t\tlocal.other.3\n\t\t%{if true ? false : true}\"gotcha\"\\n%{else}4%{endif}\n",
"simple": "${4 - 2}"
},
"skip_rules": null
"skip_rules": null,
"max_severity": "",
"min_severity": ""
}
]
}
Loading

0 comments on commit 5057073

Please sign in to comment.