| /* |
| Copyright 2018 The Kubernetes Authors. |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| package validation |
| |
| import ( |
| "strings" |
| |
| genericvalidation "k8s.io/apimachinery/pkg/api/validation" |
| "k8s.io/apimachinery/pkg/util/sets" |
| "k8s.io/apimachinery/pkg/util/validation/field" |
| "k8s.io/apiserver/pkg/util/webhook" |
| "k8s.io/kubernetes/pkg/apis/auditregistration" |
| ) |
| |
| // ValidateAuditSink validates the AuditSinks |
| func ValidateAuditSink(as *auditregistration.AuditSink) field.ErrorList { |
| allErrs := genericvalidation.ValidateObjectMeta(&as.ObjectMeta, false, genericvalidation.NameIsDNSSubdomain, field.NewPath("metadata")) |
| allErrs = append(allErrs, ValidateAuditSinkSpec(as.Spec, field.NewPath("spec"))...) |
| return allErrs |
| } |
| |
| // ValidateAuditSinkSpec validates the sink spec for audit |
| func ValidateAuditSinkSpec(s auditregistration.AuditSinkSpec, fldPath *field.Path) field.ErrorList { |
| var allErrs field.ErrorList |
| allErrs = append(allErrs, ValidatePolicy(s.Policy, fldPath.Child("policy"))...) |
| allErrs = append(allErrs, ValidateWebhook(s.Webhook, fldPath.Child("webhook"))...) |
| return allErrs |
| } |
| |
| // ValidateWebhook validates the webhook |
| func ValidateWebhook(w auditregistration.Webhook, fldPath *field.Path) field.ErrorList { |
| var allErrs field.ErrorList |
| if w.Throttle != nil { |
| allErrs = append(allErrs, ValidateWebhookThrottleConfig(w.Throttle, fldPath.Child("throttle"))...) |
| } |
| |
| cc := w.ClientConfig |
| switch { |
| case (cc.URL == nil) == (cc.Service == nil): |
| allErrs = append(allErrs, field.Required(fldPath.Child("clientConfig"), "exactly one of url or service is required")) |
| case cc.URL != nil: |
| allErrs = append(allErrs, webhook.ValidateWebhookURL(fldPath.Child("clientConfig").Child("url"), *cc.URL, false)...) |
| case cc.Service != nil: |
| allErrs = append(allErrs, webhook.ValidateWebhookService(fldPath.Child("clientConfig").Child("service"), cc.Service.Name, cc.Service.Namespace, cc.Service.Path)...) |
| } |
| return allErrs |
| } |
| |
| // ValidateWebhookThrottleConfig validates the throttle config |
| func ValidateWebhookThrottleConfig(c *auditregistration.WebhookThrottleConfig, fldPath *field.Path) field.ErrorList { |
| var allErrs field.ErrorList |
| if c.QPS != nil && *c.QPS <= 0 { |
| allErrs = append(allErrs, field.Invalid(fldPath.Child("qps"), c.QPS, "qps must be a positive number")) |
| } |
| if c.Burst != nil && *c.Burst <= 0 { |
| allErrs = append(allErrs, field.Invalid(fldPath.Child("burst"), c.Burst, "burst must be a positive number")) |
| } |
| return allErrs |
| } |
| |
| // ValidatePolicy validates the audit policy |
| func ValidatePolicy(policy auditregistration.Policy, fldPath *field.Path) field.ErrorList { |
| var allErrs field.ErrorList |
| allErrs = append(allErrs, validateStages(policy.Stages, fldPath.Child("stages"))...) |
| allErrs = append(allErrs, validateLevel(policy.Level, fldPath.Child("level"))...) |
| if policy.Level != auditregistration.LevelNone && len(policy.Stages) == 0 { |
| return field.ErrorList{field.Required(fldPath.Child("stages"), "")} |
| } |
| return allErrs |
| } |
| |
| var validLevels = sets.NewString( |
| string(auditregistration.LevelNone), |
| string(auditregistration.LevelMetadata), |
| string(auditregistration.LevelRequest), |
| string(auditregistration.LevelRequestResponse), |
| ) |
| |
| var validStages = sets.NewString( |
| string(auditregistration.StageRequestReceived), |
| string(auditregistration.StageResponseStarted), |
| string(auditregistration.StageResponseComplete), |
| string(auditregistration.StagePanic), |
| ) |
| |
| func validateLevel(level auditregistration.Level, fldPath *field.Path) field.ErrorList { |
| if string(level) == "" { |
| return field.ErrorList{field.Required(fldPath, "")} |
| } |
| if !validLevels.Has(string(level)) { |
| return field.ErrorList{field.NotSupported(fldPath, level, validLevels.List())} |
| } |
| return nil |
| } |
| |
| func validateStages(stages []auditregistration.Stage, fldPath *field.Path) field.ErrorList { |
| var allErrs field.ErrorList |
| for i, stage := range stages { |
| if !validStages.Has(string(stage)) { |
| allErrs = append(allErrs, field.Invalid(fldPath.Index(i), string(stage), "allowed stages are "+strings.Join(validStages.List(), ","))) |
| } |
| } |
| return allErrs |
| } |
| |
| // ValidateAuditSinkUpdate validates an update to the object |
| func ValidateAuditSinkUpdate(newC, oldC *auditregistration.AuditSink) field.ErrorList { |
| return ValidateAuditSink(newC) |
| } |