From 32c1150b28ebbbc433f7b673ac1f98df0ed4f13d Mon Sep 17 00:00:00 2001 From: Maxime VISONNEAU Date: Mon, 27 Sep 2021 17:56:59 +0100 Subject: [PATCH] config: new flags '--disallow-(config|annotation)-exemptions' (#636) This change follows up #635 and lets end-users decide to disallow exemption rules defined as part of the config file or the controller annotations (whether none, any or both). The main use case here is to be able to prevent users with edit privileges over a controller to add a new exemption rule through an annotation which may obfuscate the actual policies we want to enforce. Signed-off-by: Maxime VISONNEAU Co-authored-by: Robert Brennan --- cmd/polaris/root.go | 13 +++++++------ docs/cli.md | 10 ++++++---- pkg/config/config.go | 12 +++++++----- pkg/config/exemptions.go | 2 +- pkg/dashboard/dashboard.go | 14 +++++++++----- pkg/validator/schema.go | 4 +++- 6 files changed, 33 insertions(+), 22 deletions(-) diff --git a/cmd/polaris/root.go b/cmd/polaris/root.go index 60e6c1820..8e8aaf558 100644 --- a/cmd/polaris/root.go +++ b/cmd/polaris/root.go @@ -25,7 +25,7 @@ import ( ) var configPath string -var disallowExemptions bool +var disallowExemptions, disallowConfigExemptions, disallowAnnotationExemptions bool var logLevel string var auditPath string var displayName string @@ -37,7 +37,9 @@ var ( func init() { // Flags rootCmd.PersistentFlags().StringVarP(&configPath, "config", "c", "", "Location of Polaris configuration file.") - rootCmd.PersistentFlags().BoolVarP(&disallowExemptions, "disallow-exemptions", "", false, "Disallow any exemptions from configuration file.") + rootCmd.PersistentFlags().BoolVarP(&disallowExemptions, "disallow-exemptions", "", false, "Disallow any configured exemption.") + rootCmd.PersistentFlags().BoolVarP(&disallowConfigExemptions, "disallow-config-exemptions", "", false, "Disallow exemptions set within the configuration file.") + rootCmd.PersistentFlags().BoolVarP(&disallowAnnotationExemptions, "disallow-annotation-exemptions", "", false, "Disallow any exemption defined as a controller annotation.") rootCmd.PersistentFlags().StringVarP(&logLevel, "log-level", "", logrus.InfoLevel.String(), "Logrus log level.") flag.Parse() pflag.CommandLine.AddGoFlagSet(flag.CommandLine) @@ -63,10 +65,9 @@ var rootCmd = &cobra.Command{ os.Exit(1) } - if disallowExemptions { - config.DisallowExemptions = true - } - + config.DisallowExemptions = disallowExemptions + config.DisallowConfigExemptions = disallowConfigExemptions + config.DisallowAnnotationExemptions = disallowAnnotationExemptions }, Run: func(cmd *cobra.Command, args []string) { logrus.Error("You must specify a sub-command.") diff --git a/docs/cli.md b/docs/cli.md index 34ece26ff..b676dbdbf 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -19,10 +19,12 @@ webhook Runs the webhook webserver # global flags --c, --config string Location of Polaris configuration file. - --disallow-exemptions Disallow any exemptions from configuration file. - --kubeconfig string Paths to a kubeconfig. Only required if out-of-cluster. - --log-level string Logrus log level. (default "info") +-c, --config string Location of Polaris configuration file. + --disallow-exemptions Disallow any exemptions from configuration file. + --disallow-config-exemptions Disallow exemptions set within the configuration file. + --disallow-annotation-exemptions Disallow any exemption defined as a controller annotation. + --kubeconfig string Paths to a kubeconfig. Only required if out-of-cluster. + --log-level string Logrus log level. (default "info") # dashboard flags --audit-path string If specified, audits one or more YAML files instead of a cluster. diff --git a/pkg/config/config.go b/pkg/config/config.go index 9f7d4b872..2a71ad92c 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -29,11 +29,13 @@ import ( // Configuration contains all of the config for the validation checks. type Configuration struct { - DisplayName string `json:"displayName"` - Checks map[string]Severity `json:"checks"` - CustomChecks map[string]SchemaCheck `json:"customChecks"` - Exemptions []Exemption `json:"exemptions"` - DisallowExemptions bool `json:"disallowExemptions"` + DisplayName string `json:"displayName"` + Checks map[string]Severity `json:"checks"` + CustomChecks map[string]SchemaCheck `json:"customChecks"` + Exemptions []Exemption `json:"exemptions"` + DisallowExemptions bool `json:"disallowExemptions"` + DisallowConfigExemptions bool `json:"disallowConfigExemptions"` + DisallowAnnotationExemptions bool `json:"disallowAnnotationExemptions"` } // Exemption represents an exemption to normal rules diff --git a/pkg/config/exemptions.go b/pkg/config/exemptions.go index 14c0d5081..5886667dc 100644 --- a/pkg/config/exemptions.go +++ b/pkg/config/exemptions.go @@ -11,7 +11,7 @@ func (conf Configuration) IsActionable(ruleID string, objMeta metav1.Object, con if severity, ok := conf.Checks[ruleID]; !ok || !severity.IsActionable() { return false } - if conf.DisallowExemptions { + if conf.DisallowExemptions || conf.DisallowConfigExemptions { return true } for _, exemption := range conf.Exemptions { diff --git a/pkg/dashboard/dashboard.go b/pkg/dashboard/dashboard.go index 17cb179d7..09fc3eae9 100644 --- a/pkg/dashboard/dashboard.go +++ b/pkg/dashboard/dashboard.go @@ -130,13 +130,17 @@ func writeTemplate(tmpl *template.Template, data *templateData, w http.ResponseW func getConfigForQuery(base config.Configuration, query url.Values) config.Configuration { c := base - exemptions := query.Get("disallowExemptions") - if exemptions == "false" { - c.DisallowExemptions = false - } - if exemptions == "true" { + switch query.Get("disallowExemptions") { + case "true": c.DisallowExemptions = true + c.DisallowConfigExemptions = true + c.DisallowAnnotationExemptions = true + default: + c.DisallowExemptions = false + c.DisallowConfigExemptions = false + c.DisallowAnnotationExemptions = false } + return c } diff --git a/pkg/validator/schema.go b/pkg/validator/schema.go index 8c76d90e3..9beec6936 100644 --- a/pkg/validator/schema.go +++ b/pkg/validator/schema.go @@ -23,7 +23,9 @@ type schemaTestCase struct { } func resolveCheck(conf *config.Configuration, checkID string, test schemaTestCase) (*config.SchemaCheck, error) { - if !conf.DisallowExemptions && hasExemptionAnnotation(test.Resource.ObjectMeta, checkID) { + if !conf.DisallowExemptions && + !conf.DisallowAnnotationExemptions && + hasExemptionAnnotation(test.Resource.ObjectMeta, checkID) { return nil, nil } check, ok := conf.CustomChecks[checkID]