From 4f626677757e8d16b6f56565c86707b4eba14b46 Mon Sep 17 00:00:00 2001 From: wawa0210 Date: Mon, 11 Jan 2021 13:02:06 +0800 Subject: [PATCH] Fix RBAC resource name verification Signed-off-by: wawa0210 --- pkg/chartutil/validate_name.go | 26 ++++++++++++++++++++++++++ pkg/chartutil/validate_name_test.go | 21 +++++++++++++++++++++ pkg/lint/rules/template.go | 15 +++++++++++---- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/pkg/chartutil/validate_name.go b/pkg/chartutil/validate_name.go index 913a477cf..d424fd1c6 100644 --- a/pkg/chartutil/validate_name.go +++ b/pkg/chartutil/validate_name.go @@ -19,6 +19,7 @@ package chartutil import ( "fmt" "regexp" + "strings" "github.com/pkg/errors" ) @@ -35,6 +36,12 @@ import ( // https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names var validName = regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`) +// nameMayNotBe specifies strings that cannot be used as names specified as path segments (like the REST API or etcd store) +var nameMayNotBe = []string{".", ".."} + +// nameMayNotContain specifies substrings that cannot be used in names specified as path segments (like the REST API or etcd store) +var nameMayNotContain = []string{"/", "%"} + var ( // errMissingName indicates that a release (name) was not provided. errMissingName = errors.New("no name provided") @@ -102,3 +109,22 @@ func ValidateMetadataName(name string) error { } return nil } + +// ValidateRBACMetadataName validate the name field of a Kubernetes rbac metadata object. +func ValidateRBACMetadataName(name string) error { + if name == "" { + return errMissingName + } + for _, illegalName := range nameMayNotBe { + if name == illegalName { + return errors.Errorf("invalid release name , cannot be any of the following characters: %s", nameMayNotBe) + } + } + + for _, illegalContent := range nameMayNotContain { + if strings.Contains(name, illegalContent) { + return errors.Errorf("invalid release name , cannot contain the following characters: %s", nameMayNotContain) + } + } + return nil +} diff --git a/pkg/chartutil/validate_name_test.go b/pkg/chartutil/validate_name_test.go index 5f0792f94..e2cbea5f0 100644 --- a/pkg/chartutil/validate_name_test.go +++ b/pkg/chartutil/validate_name_test.go @@ -89,3 +89,24 @@ func TestValidateMetadataName(t *testing.T) { } } } + +func TestValidateRBACMetadataName(t *testing.T) { + names := map[string]bool{ + "": false, + ".": false, + "..": false, + "foo/": false, + "foo%": false, + "foo/%": false, + "foo": true, + } + for input, expectPass := range names { + if err := ValidateRBACMetadataName(input); (err == nil) != expectPass { + st := "fail" + if expectPass { + st = "succeed" + } + t.Errorf("Expected %q to %s", input, st) + } + } +} diff --git a/pkg/lint/rules/template.go b/pkg/lint/rules/template.go index 10121c108..a1f19d4ef 100644 --- a/pkg/lint/rules/template.go +++ b/pkg/lint/rules/template.go @@ -206,11 +206,18 @@ func validateMetadataName(obj *K8sYamlStruct) error { if len(obj.Metadata.Name) == 0 || len(obj.Metadata.Name) > 253 { return fmt.Errorf("object name must be between 0 and 253 characters: %q", obj.Metadata.Name) } - // This will return an error if the characters do not abide by the standard OR if the - // name is left empty. - if err := chartutil.ValidateMetadataName(obj.Metadata.Name); err != nil { - return errors.Wrapf(err, "object name does not conform to Kubernetes naming requirements: %q", obj.Metadata.Name) + if obj.APIVersion == "rbac.authorization.k8s.io/v1" { + if err := chartutil.ValidateRBACMetadataName(obj.Metadata.Name); err != nil { + return errors.Wrapf(err, "object name does not conform to Kubernetes naming requirements: %q", obj.Metadata.Name) + } + } else { + // This will return an error if the characters do not abide by the standard OR if the + // name is left empty. + if err := chartutil.ValidateMetadataName(obj.Metadata.Name); err != nil { + return errors.Wrapf(err, "object name does not conform to Kubernetes naming requirements: %q", obj.Metadata.Name) + } } + return nil }