k8s.io/apiserver@v0.31.1/pkg/apis/audit/validation/validation.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package validation 18 19 import ( 20 "strings" 21 22 "k8s.io/apimachinery/pkg/api/validation" 23 "k8s.io/apimachinery/pkg/util/validation/field" 24 "k8s.io/apiserver/pkg/apis/audit" 25 ) 26 27 // ValidatePolicy validates the audit policy 28 func ValidatePolicy(policy *audit.Policy) field.ErrorList { 29 var allErrs field.ErrorList 30 allErrs = append(allErrs, validateOmitStages(policy.OmitStages, field.NewPath("omitStages"))...) 31 rulePath := field.NewPath("rules") 32 for i, rule := range policy.Rules { 33 allErrs = append(allErrs, validatePolicyRule(rule, rulePath.Index(i))...) 34 } 35 return allErrs 36 } 37 38 func validatePolicyRule(rule audit.PolicyRule, fldPath *field.Path) field.ErrorList { 39 var allErrs field.ErrorList 40 allErrs = append(allErrs, validateLevel(rule.Level, fldPath.Child("level"))...) 41 allErrs = append(allErrs, validateNonResourceURLs(rule.NonResourceURLs, fldPath.Child("nonResourceURLs"))...) 42 allErrs = append(allErrs, validateResources(rule.Resources, fldPath.Child("resources"))...) 43 allErrs = append(allErrs, validateOmitStages(rule.OmitStages, fldPath.Child("omitStages"))...) 44 45 if len(rule.NonResourceURLs) > 0 { 46 if len(rule.Resources) > 0 || len(rule.Namespaces) > 0 { 47 allErrs = append(allErrs, field.Invalid(fldPath.Child("nonResourceURLs"), rule.NonResourceURLs, "rules cannot apply to both regular resources and non-resource URLs")) 48 } 49 } 50 51 return allErrs 52 } 53 54 var validLevels = []string{ 55 string(audit.LevelNone), 56 string(audit.LevelMetadata), 57 string(audit.LevelRequest), 58 string(audit.LevelRequestResponse), 59 } 60 61 var validOmitStages = []string{ 62 string(audit.StageRequestReceived), 63 string(audit.StageResponseStarted), 64 string(audit.StageResponseComplete), 65 string(audit.StagePanic), 66 } 67 68 func validateLevel(level audit.Level, fldPath *field.Path) field.ErrorList { 69 switch level { 70 case audit.LevelNone, audit.LevelMetadata, audit.LevelRequest, audit.LevelRequestResponse: 71 return nil 72 case "": 73 return field.ErrorList{field.Required(fldPath, "")} 74 default: 75 return field.ErrorList{field.NotSupported(fldPath, level, validLevels)} 76 } 77 } 78 79 func validateNonResourceURLs(urls []string, fldPath *field.Path) field.ErrorList { 80 var allErrs field.ErrorList 81 for i, url := range urls { 82 if url == "*" { 83 continue 84 } 85 86 if !strings.HasPrefix(url, "/") { 87 allErrs = append(allErrs, field.Invalid(fldPath.Index(i), url, "non-resource URL rules must begin with a '/' character")) 88 } 89 90 if url != "" && strings.ContainsRune(url[:len(url)-1], '*') { 91 allErrs = append(allErrs, field.Invalid(fldPath.Index(i), url, "non-resource URL wildcards '*' must be the final character of the rule")) 92 } 93 } 94 return allErrs 95 } 96 97 func validateResources(groupResources []audit.GroupResources, fldPath *field.Path) field.ErrorList { 98 var allErrs field.ErrorList 99 for _, groupResource := range groupResources { 100 // The empty string represents the core API group. 101 if len(groupResource.Group) != 0 { 102 // Group names must be lower case and be valid DNS subdomains. 103 // reference: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md 104 // an error is returned for group name like rbac.authorization.k8s.io/v1beta1 105 // rbac.authorization.k8s.io is the valid one 106 if msgs := validation.NameIsDNSSubdomain(groupResource.Group, false); len(msgs) != 0 { 107 allErrs = append(allErrs, field.Invalid(fldPath.Child("group"), groupResource.Group, strings.Join(msgs, ","))) 108 } 109 } 110 111 if len(groupResource.ResourceNames) > 0 && len(groupResource.Resources) == 0 { 112 allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceNames"), groupResource.ResourceNames, "using resourceNames requires at least one resource")) 113 } 114 } 115 return allErrs 116 } 117 118 func validateOmitStages(omitStages []audit.Stage, fldPath *field.Path) field.ErrorList { 119 var allErrs field.ErrorList 120 for i, stage := range omitStages { 121 valid := false 122 for _, validOmitStage := range validOmitStages { 123 if string(stage) == validOmitStage { 124 valid = true 125 break 126 } 127 } 128 if !valid { 129 allErrs = append(allErrs, field.Invalid(fldPath.Index(i), string(stage), "allowed stages are "+strings.Join(validOmitStages, ","))) 130 } 131 } 132 return allErrs 133 }