webhook 配置校验
initConfigValidation
func (s *Server) initConfigValidation(args *PilotArgs) error {
...
log.Info("initializing config validator")
// always start the validation server
params := server.Options{
Schemas: collections.Istio,
DomainSuffix: args.RegistryOptions.KubeOptions.DomainSuffix,
Mux: s.httpsMux,
}
// 根据参数初始化Server
whServer, err := server.New(params)
if err != nil {
return err
}
s.addStartFunc(func(stop <-chan struct{}) error {
whServer.Run(stop)
return nil
})
// 是否校验webhook
if webhookConfigName := validationWebhookConfigName.Get(); webhookConfigName != "" && s.kubeClient != nil {
if webhookConfigName == validationWebhookConfigNameTemplate {
webhookConfigName = strings.ReplaceAll(validationWebhookConfigNameTemplate, validationWebhookConfigNameTemplateVar, args.Namespace)
}
caBundlePath := s.caBundlePath
if hasCustomTLSCerts(args.ServerOptions.TLSOptions) {
caBundlePath = args.ServerOptions.TLSOptions.CaCertFile
}
o := controller.Options{
WatchedNamespace: args.Namespace,
CAPath: caBundlePath,
WebhookConfigName: webhookConfigName,
ServiceName: "istiod",
}
// 初始化webhook controller
whController, err := controller.New(o, s.kubeClient)
if err != nil {
log.Errorf("failed to start validation controller: %v", err)
return err
}
s.addTerminatingStartFunc(func(stop <-chan struct{}) error {
le := leaderelection.NewLeaderElection(args.Namespace, args.PodName, leaderelection.ValidationController, s.kubeClient)
le.AddRunFunction(func(leaderStop <-chan struct{}) {
log.Infof("Starting validation controller")
// 启动controller
whController.Start(leaderStop)
})
le.Run(stop)
return nil
})
}
return nil
}
// New creates a new instance of the admission webhook server.
func New(p Options) (*Webhook, error) {
if p.Mux == nil {
scope.Error("mux not set correctly")
return nil, errors.New("expected mux to be passed, but was not passed")
}
wh := &Webhook{
schemas: p.Schemas,
}
p.Mux.HandleFunc("/validate", wh.serveValidate)
// old handlers retained backwards compatibility during upgrades
p.Mux.HandleFunc("/admitpilot", wh.serveAdmitPilot)
return wh, nil
}
校验规则
func (wh *Webhook) admitPilot(request *kube.AdmissionRequest) *kube.AdmissionResponse {
switch request.Operation {
case kube.Create, kube.Update:
default:
scope.Warnf("Unsupported webhook operation %v", request.Operation)
reportValidationFailed(request, reasonUnsupportedOperation)
return &kube.AdmissionResponse{Allowed: true}
}
var obj crd.IstioKind
// 是否是istio类型,符合istio的spec规范
if err := json.Unmarshal(request.Object.Raw, &obj); err != nil {
scope.Infof("cannot decode configuration: %v", err)
reportValidationFailed(request, reasonYamlDecodeError)
return toAdmissionResponse(fmt.Errorf("cannot decode configuration: %v", err))
}
gvk := obj.GroupVersionKind()
// 1️v1beta1转化为v1alpha3.
if gvk.Group == "networking.istio.io" && gvk.Version == "v1beta1" {
gvk.Version = "v1alpha3"
}
// 查找对应类型的scheme
s, exists := wh.schemas.FindByGroupVersionKind(resource.FromKubernetesGVK(&gvk))
if !exists {
scope.Infof("unrecognized type %v", obj.Kind)
reportValidationFailed(request, reasonUnknownType)
return toAdmissionResponse(fmt.Errorf("unrecognized type %v", obj.Kind))
}
// 查看是否能转换为对应的CRD
out, err := crd.ConvertObject(s, &obj, wh.domainSuffix)
if err != nil {
scope.Infof("error decoding configuration: %v", err)
reportValidationFailed(request, reasonCRDConversionError)
return toAdmissionResponse(fmt.Errorf("error decoding configuration: %v", err))
}
// 查看是否满足配置要求
warnings, err := s.Resource().ValidateConfig(*out)
if err != nil {
scope.Infof("configuration is invalid: %v", err)
reportValidationFailed(request, reasonInvalidConfig)
return toAdmissionResponse(fmt.Errorf("configuration is invalid: %v", err))
}
// 查看是否包含未知字段
if reason, err := checkFields(request.Object.Raw, request.Kind.Kind, request.Namespace, obj.Name); err != nil {
reportValidationFailed(request, reason)
return toAdmissionResponse(err)
}
// 写入指标
reportValidationPass(request)
// 返回AdmissionResponse
return &kube.AdmissionResponse{Allowed: true, Warnings: toKubeWarnings(warnings)}
}
如果启用了webhook配置校验则将通过
检查mutatingwebhookc 配置是否有效填充CABundle和FailurePolicy
func (c *Controller) updateValidatingWebhookConfiguration(caBundle []byte, failurePolicy kubeApiAdmission.FailurePolicyType) error {
...
updated := current.DeepCopyObject().(*kubeApiAdmission.ValidatingWebhookConfiguration)
for i := range updated.Webhooks {
updated.Webhooks[i].ClientConfig.CABundle = caBundle
updated.Webhooks[i].FailurePolicy = &failurePolicy
}
if !reflect.DeepEqual(updated, current) {
latest, err := c.client.AdmissionregistrationV1beta1().
ValidatingWebhookConfigurations().Update(context.TODO(), updated, kubeApiMeta.UpdateOptions{})
...
}
Last updated