Merge pull request #47784 from CaoShuFeng/rule_validate

Automatic merge from submit-queue (batch tested with PRs 47784, 47793, 48334, 48435, 48354)

add validate for advanced audit policy

This change checks group name and non-resrouce URLs format for audit
policy.

**Release note**:

```
add validate for advanced audit policy, kube-apiserver will do a stricter validation and will break existing users with invalid configs.
```
This commit is contained in:
Kubernetes Submit Queue 2017-07-03 10:41:47 -07:00 committed by GitHub
commit 55261d7955
3 changed files with 72 additions and 1 deletions

View File

@ -21,6 +21,7 @@ go_library(
srcs = ["validation.go"],
tags = ["automanaged"],
deps = [
"//vendor/k8s.io/apimachinery/pkg/api/validation:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/audit:go_default_library",
],

View File

@ -17,6 +17,9 @@ limitations under the License.
package validation
import (
"strings"
"k8s.io/apimachinery/pkg/api/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/apiserver/pkg/apis/audit"
)
@ -33,6 +36,8 @@ func ValidatePolicy(policy *audit.Policy) field.ErrorList {
func validatePolicyRule(rule audit.PolicyRule, fldPath *field.Path) field.ErrorList {
var allErrs field.ErrorList
allErrs = append(allErrs, validateLevel(rule.Level, fldPath.Child("level"))...)
allErrs = append(allErrs, validateNonResourceURLs(rule.NonResourceURLs, fldPath.Child("nonResourceURLs"))...)
allErrs = append(allErrs, validateResources(rule.Resources, fldPath.Child("resources"))...)
if len(rule.NonResourceURLs) > 0 {
if len(rule.Resources) > 0 || len(rule.Namespaces) > 0 {
@ -60,3 +65,40 @@ func validateLevel(level audit.Level, fldPath *field.Path) field.ErrorList {
return field.ErrorList{field.NotSupported(fldPath, level, validLevels)}
}
}
func validateNonResourceURLs(urls []string, fldPath *field.Path) field.ErrorList {
var allErrs field.ErrorList
for i, url := range urls {
if url == "*" {
continue
}
if !strings.HasPrefix(url, "/") {
allErrs = append(allErrs, field.Invalid(fldPath.Index(i), url, "non-resource URL rules must begin with a '/' character"))
}
if url != "" && strings.ContainsRune(url[:len(url)-1], '*') {
allErrs = append(allErrs, field.Invalid(fldPath.Index(i), url, "non-resource URL wildcards '*' must be the final character of the rule"))
}
}
return allErrs
}
func validateResources(groupResources []audit.GroupResources, fldPath *field.Path) field.ErrorList {
var allErrs field.ErrorList
for _, groupResource := range groupResources {
// The empty string represents the core API group.
if len(groupResource.Group) == 0 {
continue
}
// Group names must be lower case and be valid DNS subdomains.
// reference: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md
// an error is returned for group name like rbac.authorization.k8s.io/v1beta1
// rbac.authorization.k8s.io is the valid one
if msgs := validation.NameIsDNSSubdomain(groupResource.Group, false); len(msgs) != 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("group"), groupResource.Group, strings.Join(msgs, ",")))
}
}
return allErrs
}

View File

@ -32,7 +32,7 @@ func TestValidatePolicy(t *testing.T) {
}, { // Specific request
Level: audit.LevelRequestResponse,
Verbs: []string{"get"},
Resources: []audit.GroupResources{{Resources: []string{"secrets"}}},
Resources: []audit.GroupResources{{Group: "rbac.authorization.k8s.io", Resources: []string{"roles", "rolebindings"}}},
Namespaces: []string{"kube-system"},
}, { // Some non-resource URLs
Level: audit.LevelMetadata,
@ -41,6 +41,7 @@ func TestValidatePolicy(t *testing.T) {
"/logs*",
"/healthz*",
"/metrics",
"*",
},
},
}
@ -73,6 +74,33 @@ func TestValidatePolicy(t *testing.T) {
Level: audit.LevelMetadata,
Resources: []audit.GroupResources{{Resources: []string{"secrets"}}},
NonResourceURLs: []string{"/logs*"},
}, { // invalid group name
Level: audit.LevelMetadata,
Resources: []audit.GroupResources{{Group: "rbac.authorization.k8s.io/v1beta1", Resources: []string{"roles"}}},
}, { // invalid non-resource URLs
Level: audit.LevelMetadata,
NonResourceURLs: []string{
"logs",
"/healthz*",
},
}, { // empty non-resource URLs
Level: audit.LevelMetadata,
NonResourceURLs: []string{
"",
"/healthz*",
},
}, { // invalid non-resource URLs with multi "*"
Level: audit.LevelMetadata,
NonResourceURLs: []string{
"/logs/*/*",
"/metrics",
},
}, { // invalid non-resrouce URLs with "*" not in the end
Level: audit.LevelMetadata,
NonResourceURLs: []string{
"/logs/*.log",
"/metrics",
},
},
}
errorCases := []audit.Policy{}