Repository: tenable/terrascan (language: python)

Issue:
Make saving of "admission request" configurable via an option in the config file for the validating admission webhook
Currently terrascan saves all the incoming admission requests into it's database. We need to give users an option to choose whether to save admission requests or not. This can be done by a newly introduced flag `save-requests` in the `k8s-admission-control` section of the config file


Discussion / hints:

Fix patch:
diff --git a/pkg/config/config-reader.go b/pkg/config/config-reader.go
index bb421a093..520e7b097 100644
--- a/pkg/config/config-reader.go
+++ b/pkg/config/config-reader.go
@@ -93,7 +93,7 @@ func (r TerrascanConfigReader) getSeverity() Severity {
 	return r.config.Severity
 }
 
-// GetK8sDenyRules will return the k8s deny rules specified in the terrascan config file
-func (r TerrascanConfigReader) GetK8sDenyRules() K8sDenyRules {
-	return r.config.K8sDenyRules
+// GetK8sAdmissionControl will return the k8s deny rules specified in the terrascan config file
+func (r TerrascanConfigReader) GetK8sAdmissionControl() K8sAdmissionControl {
+	return r.config.K8sAdmissionControl
 }
diff --git a/pkg/config/global.go b/pkg/config/global.go
index 378434ace..14e590c92 100644
--- a/pkg/config/global.go
+++ b/pkg/config/global.go
@@ -111,6 +111,8 @@ func LoadGlobalConfig(configFile string) error {
 		global.Category.List = configReader.getCategory().List
 	}
 
+	global.K8sAdmissionControl = configReader.GetK8sAdmissionControl()
+
 	zap.S().Debugf("global config loaded")
 
 	return nil
@@ -160,3 +162,8 @@ func GetCategoryList() []string {
 func GetNotifications() map[string]Notifier {
 	return global.Notifications
 }
+
+// GetK8sAdmissionControl returns kubernetes admission control configuration
+func GetK8sAdmissionControl() K8sAdmissionControl {
+	return global.K8sAdmissionControl
+}
diff --git a/pkg/config/types.go b/pkg/config/types.go
index bea34ac17..4b0d4b60c 100644
--- a/pkg/config/types.go
+++ b/pkg/config/types.go
@@ -21,12 +21,12 @@ var global *TerrascanConfig = &TerrascanConfig{}
 
 // TerrascanConfig struct defines global variables/configurations across terrascan
 type TerrascanConfig struct {
-	Policy        `toml:"policy,omitempty"`
-	Notifications map[string]Notifier `toml:"notifications,omitempty"`
-	Rules         `toml:"rules,omitempty"`
-	Category      `toml:"category,omitempty"`
-	Severity      `toml:"severity,omitempty"`
-	K8sDenyRules  `toml:"k8s-deny-rules,omitempty"`
+	Policy              `toml:"policy,omitempty"`
+	Notifications       map[string]Notifier `toml:"notifications,omitempty"`
+	Rules               `toml:"rules,omitempty"`
+	Category            `toml:"category,omitempty"`
+	Severity            `toml:"severity,omitempty"`
+	K8sAdmissionControl `toml:"k8s-admission-control,omitempty"`
 }
 
 // Category defines the categories of violations that you want to be reported
@@ -63,8 +63,9 @@ type Rules struct {
 	SkipRules []string `toml:"skip-rules,omitempty"`
 }
 
-// K8sDenyRules deny rules in the terrascan config file
-type K8sDenyRules struct {
+// K8sAdmissionControl deny rules in the terrascan config file
+type K8sAdmissionControl struct {
 	DeniedSeverity string   `toml:"denied-severity,omitempty"`
 	Categories     []string `toml:"denied-categories,omitempty"`
+	SaveRequests   bool     `toml:"save-requests,omitempty"`
 }
diff --git a/pkg/http-server/webhook-scan-logs.go b/pkg/http-server/webhook-scan-logs.go
index db79afe21..53b0fa225 100644
--- a/pkg/http-server/webhook-scan-logs.go
+++ b/pkg/http-server/webhook-scan-logs.go
@@ -23,6 +23,7 @@ import (
 	"net/http"
 	"time"
 
+	"github.com/accurics/terrascan/pkg/config"
 	"github.com/accurics/terrascan/pkg/k8s/dblogs"
 	"github.com/accurics/terrascan/pkg/results"
 	"github.com/gorilla/mux"
@@ -215,6 +216,10 @@ func (g *APIHandler) getLogReasoning(log dblogs.WebhookScanLog) string {
 func (g *APIHandler) getLogRequest(log dblogs.WebhookScanLog) string {
 	var review webhookDisplayedReview
 
+	if !config.GetK8sAdmissionControl().SaveRequests {
+		return "{}"
+	}
+
 	err := json.Unmarshal([]byte(log.Request), &review)
 
 	if err != nil {
diff --git a/pkg/k8s/admission-webhook/validating-webhook.go b/pkg/k8s/admission-webhook/validating-webhook.go
index a6dfc894c..0a9fa40ef 100644
--- a/pkg/k8s/admission-webhook/validating-webhook.go
+++ b/pkg/k8s/admission-webhook/validating-webhook.go
@@ -212,12 +212,12 @@ func (w ValidatingWebhook) getDenyViolations(output runtime.Output) ([]results.V
 		return nil, err
 	}
 
-	denyViolations := w.getDeniedViolations(*output.Violations.ViolationStore, configReader.GetK8sDenyRules())
+	denyViolations := w.getDeniedViolations(*output.Violations.ViolationStore, configReader.GetK8sAdmissionControl())
 
 	return denyViolations, nil
 }
 
-func (w ValidatingWebhook) getDeniedViolations(violations results.ViolationStore, denyRules config.K8sDenyRules) []results.Violation {
+func (w ValidatingWebhook) getDeniedViolations(violations results.ViolationStore, denyRules config.K8sAdmissionControl) []results.Violation {
 	// Check whether one of the violations matches the deny violations configuration
 
 	var denyViolations []results.Violation
@@ -241,6 +241,7 @@ func (w ValidatingWebhook) logWebhook(output runtime.Output,
 	var (
 		currentTime             = time.Now()
 		deniedViolationsEncoded string
+		requestBody             string
 	)
 
 	// encode denied violations into a string
@@ -253,10 +254,14 @@ func (w ValidatingWebhook) logWebhook(output runtime.Output,
 
 	encodedViolationsSummary, _ := json.Marshal(output.Violations.ViolationStore)
 
+	if config.GetK8sAdmissionControl().SaveRequests {
+		requestBody = string(w.requestBody)
+	}
+
 	// insert the webhook log into db
 	err := w.dblogger.Log(dblogs.WebhookScanLog{
 		UID:                uid,
-		Request:            string(w.requestBody),
+		Request:            requestBody,
 		Allowed:            allowed,
 		DeniableViolations: deniedViolationsEncoded,
 		ViolationsSummary:  string(encodedViolationsSummary),
@@ -310,7 +315,7 @@ type webhookDenyRuleMatcher struct {
 }
 
 // This class should check if one of the violations found is relevant for the specified K8s deny rules
-func (g *webhookDenyRuleMatcher) match(violation results.Violation, denyRules config.K8sDenyRules) bool {
+func (g *webhookDenyRuleMatcher) match(violation results.Violation, denyRules config.K8sAdmissionControl) bool {
 
 	if denyRules.DeniedSeverity == "" && len(denyRules.Categories) == 0 {
 		return false


Test patch:
diff --git a/pkg/http-server/k8s_testdata/config-deny-category.toml b/pkg/http-server/k8s_testdata/config-deny-category.toml
index b3d4204f7..82a43f13d 100644
--- a/pkg/http-server/k8s_testdata/config-deny-category.toml
+++ b/pkg/http-server/k8s_testdata/config-deny-category.toml
@@ -1,4 +1,4 @@
-[k8s-deny-rules]
+[k8s-admission-control]
   denied-categories = [
       "Identity and Access Management",
       "Network Security",
diff --git a/pkg/http-server/k8s_testdata/config-deny-high.toml b/pkg/http-server/k8s_testdata/config-deny-high.toml
index 5046654bc..819365197 100644
--- a/pkg/http-server/k8s_testdata/config-deny-high.toml
+++ b/pkg/http-server/k8s_testdata/config-deny-high.toml
@@ -1,5 +1,5 @@
 [severity]
 level = "medium"
 
-[k8s-deny-rules]
+[k8s-admission-control]
   denied-severity = "high"
diff --git a/pkg/http-server/k8s_testdata/config-deny-non-existing-category.toml b/pkg/http-server/k8s_testdata/config-deny-non-existing-category.toml
index d38bc482e..046afc448 100644
--- a/pkg/http-server/k8s_testdata/config-deny-non-existing-category.toml
+++ b/pkg/http-server/k8s_testdata/config-deny-non-existing-category.toml
@@ -1,7 +1,7 @@
 [severity]
 level = "medium"
 
-[k8s-deny-rules]
+[k8s-admission-control]
   denied-categories = [
       "Hola",
       "Invalid",
diff --git a/pkg/http-server/webhook-scan_test.go b/pkg/http-server/webhook-scan_test.go
index b13f53a0e..6b390ad36 100644
--- a/pkg/http-server/webhook-scan_test.go
+++ b/pkg/http-server/webhook-scan_test.go
@@ -217,15 +217,15 @@ func TestUWebhooks(t *testing.T) {
 
 			if res.Code == http.StatusOK {
 				if tt.warnings && response.Response.Warnings == nil {
-					t.Errorf("Expected warnings but received None")
+					t.Errorf("expected warnings but received None")
 				}
 
 				if tt.allowed != response.Response.Allowed {
-					t.Errorf("Mismach in allowed. Got: %v, expected: %v", response.Response.Allowed, tt.allowed)
+					t.Errorf("mismatch in allowed. Got: %v, expected: %v", response.Response.Allowed, tt.allowed)
 				}
 
 				if tt.statusCode != 0 && tt.statusCode != response.Response.Result.Code {
-					t.Errorf("Mismach Statud code Got: %v, expected: %v", response.Response.Result.Code, tt.statusCode)
+					t.Errorf("mismatch Status code Got: %v, expected: %v", response.Response.Result.Code, tt.statusCode)
 				}
 
 				if tt.warnings || tt.statusMessage {
@@ -240,7 +240,7 @@ func TestUWebhooks(t *testing.T) {
 					expectedLogPath := fmt.Sprintf("For more details please visit %q", subLogPath)
 
 					if logPath != expectedLogPath {
-						t.Errorf("Mismach Log path. Got: %v, expected: %v", logPath, expectedLogPath)
+						t.Errorf("mismatch Log path. Got: %v, expected: %v", logPath, expectedLogPath)
 					}
 				}
 			}
diff --git a/pkg/k8s/admission-webhook/webhook-deny-rule-matcher_test.go b/pkg/k8s/admission-webhook/webhook-deny-rule-matcher_test.go
index 3b613b6a0..c0c58d6a8 100644
--- a/pkg/k8s/admission-webhook/webhook-deny-rule-matcher_test.go
+++ b/pkg/k8s/admission-webhook/webhook-deny-rule-matcher_test.go
@@ -33,7 +33,7 @@ func TestDenyRuleMatcher(t *testing.T) {
 		ruleSeverity   string
 		ruleCategory   string
 		ruleName       string
-		k8sDenyRules   config.K8sDenyRules
+		k8sDenyRules   config.K8sAdmissionControl
 		expectedResult bool
 	}{
 		{
@@ -48,7 +48,7 @@ func TestDenyRuleMatcher(t *testing.T) {
 			ruleSeverity:   testMediumSeverity,
 			ruleCategory:   testCategory,
 			ruleName:       testRuleName,
-			k8sDenyRules:   config.K8sDenyRules{DeniedSeverity: testMediumSeverity},
+			k8sDenyRules:   config.K8sAdmissionControl{DeniedSeverity: testMediumSeverity},
 			expectedResult: true,
 		},
 
@@ -57,7 +57,7 @@ func TestDenyRuleMatcher(t *testing.T) {
 			ruleSeverity:   testMediumSeverity,
 			ruleCategory:   testCategory,
 			ruleName:       testRuleName,
-			k8sDenyRules:   config.K8sDenyRules{DeniedSeverity: "LOW"},
+			k8sDenyRules:   config.K8sAdmissionControl{DeniedSeverity: "LOW"},
 			expectedResult: true,
 		},
 		{
@@ -65,7 +65,7 @@ func TestDenyRuleMatcher(t *testing.T) {
 			ruleSeverity:   testMediumSeverity,
 			ruleCategory:   testCategory,
 			ruleName:       testRuleName,
-			k8sDenyRules:   config.K8sDenyRules{DeniedSeverity: "High"},
+			k8sDenyRules:   config.K8sAdmissionControl{DeniedSeverity: "High"},
 			expectedResult: false,
 		},
 		{
@@ -73,7 +73,7 @@ func TestDenyRuleMatcher(t *testing.T) {
 			ruleSeverity:   testMediumSeverity,
 			ruleCategory:   testCategory,
 			ruleName:       testRuleName,
-			k8sDenyRules:   config.K8sDenyRules{Categories: []string{"WRONG!"}},
+			k8sDenyRules:   config.K8sAdmissionControl{Categories: []string{"WRONG!"}},
 			expectedResult: false,
 		},
 
@@ -82,7 +82,7 @@ func TestDenyRuleMatcher(t *testing.T) {
 			ruleSeverity:   testMediumSeverity,
 			ruleCategory:   testCategory,
 			ruleName:       testRuleName,
-			k8sDenyRules:   config.K8sDenyRules{Categories: []string{"WRONG!", testCategory}},
+			k8sDenyRules:   config.K8sAdmissionControl{Categories: []string{"WRONG!", testCategory}},
 			expectedResult: true,
 		},
 		{
@@ -90,7 +90,7 @@ func TestDenyRuleMatcher(t *testing.T) {
 			ruleSeverity:   testMediumSeverity,
 			ruleCategory:   testCategory,
 			ruleName:       testRuleName,
-			k8sDenyRules:   config.K8sDenyRules{Categories: []string{"WRONG!", testCategory}, DeniedSeverity: "HIGH"},
+			k8sDenyRules:   config.K8sAdmissionControl{Categories: []string{"WRONG!", testCategory}, DeniedSeverity: "HIGH"},
 			expectedResult: true,
 		},
 	}