diff --git a/plugin/pkg/auth/authorizer/webhook/webhook.go b/plugin/pkg/auth/authorizer/webhook/webhook.go index 66f4bbd027e..3d662f33527 100644 --- a/plugin/pkg/auth/authorizer/webhook/webhook.go +++ b/plugin/pkg/auth/authorizer/webhook/webhook.go @@ -19,35 +19,24 @@ package webhook import ( "errors" - "fmt" - "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/unversioned" - "k8s.io/kubernetes/pkg/apimachinery/registered" "k8s.io/kubernetes/pkg/apis/authorization/v1beta1" "k8s.io/kubernetes/pkg/auth/authorizer" - "k8s.io/kubernetes/pkg/client/restclient" - "k8s.io/kubernetes/pkg/client/unversioned/clientcmd" - "k8s.io/kubernetes/pkg/runtime" - runtimeserializer "k8s.io/kubernetes/pkg/runtime/serializer" - "k8s.io/kubernetes/pkg/runtime/serializer/json" - "k8s.io/kubernetes/pkg/runtime/serializer/versioning" + "k8s.io/kubernetes/plugin/pkg/webhook" _ "k8s.io/kubernetes/pkg/apis/authorization/install" ) var ( - encodeVersions = []unversioned.GroupVersion{v1beta1.SchemeGroupVersion} - decodeVersions = []unversioned.GroupVersion{v1beta1.SchemeGroupVersion} - - requireEnabled = []unversioned.GroupVersion{v1beta1.SchemeGroupVersion} + groupVersions = []unversioned.GroupVersion{v1beta1.SchemeGroupVersion} ) // Ensure Webhook implements the authorizer.Authorizer interface. var _ authorizer.Authorizer = (*WebhookAuthorizer)(nil) type WebhookAuthorizer struct { - restClient *restclient.RESTClient + *webhook.GenericWebhook } // New creates a new WebhookAuthorizer from the provided kubeconfig file. @@ -71,37 +60,11 @@ type WebhookAuthorizer struct { // For additional HTTP configuration, refer to the kubeconfig documentation // http://kubernetes.io/v1.1/docs/user-guide/kubeconfig-file.html. func New(kubeConfigFile string) (*WebhookAuthorizer, error) { - - for _, groupVersion := range requireEnabled { - if !registered.IsEnabledVersion(groupVersion) { - return nil, fmt.Errorf("webhook authz plugin requires enabling extension resource: %s", groupVersion) - } - } - - loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() - loadingRules.ExplicitPath = kubeConfigFile - loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{}) - - clientConfig, err := loader.ClientConfig() + gw, err := webhook.NewGenericWebhook(kubeConfigFile, groupVersions) if err != nil { return nil, err } - - serializer := json.NewSerializer(json.DefaultMetaFactory, api.Scheme, runtime.ObjectTyperToTyper(api.Scheme), false) - codec := versioning.NewCodecForScheme(api.Scheme, serializer, serializer, encodeVersions, decodeVersions) - clientConfig.ContentConfig.NegotiatedSerializer = runtimeserializer.NegotiatedSerializerWrapper( - runtime.SerializerInfo{Serializer: codec}, - runtime.StreamSerializerInfo{}, - ) - - restClient, err := restclient.UnversionedRESTClientFor(clientConfig) - if err != nil { - return nil, err - } - - // TODO(ericchiang): Can we ensure remote service is reachable? - - return &WebhookAuthorizer{restClient}, nil + return &WebhookAuthorizer{gw}, nil } // Authorize makes a REST request to the remote service describing the attempted action as a JSON @@ -171,7 +134,7 @@ func (w *WebhookAuthorizer) Authorize(attr authorizer.Attributes) (err error) { Verb: attr.GetVerb(), } } - result := w.restClient.Post().Body(r).Do() + result := w.RestClient.Post().Body(r).Do() if err := result.Error(); err != nil { return err } diff --git a/plugin/pkg/webhook/webhook.go b/plugin/pkg/webhook/webhook.go new file mode 100644 index 00000000000..d00d54a5e5a --- /dev/null +++ b/plugin/pkg/webhook/webhook.go @@ -0,0 +1,68 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 webhook implements a generic HTTP webhook plugin. +package webhook + +import ( + "fmt" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/client/restclient" + "k8s.io/kubernetes/pkg/client/unversioned/clientcmd" + "k8s.io/kubernetes/pkg/runtime" + runtimeserializer "k8s.io/kubernetes/pkg/runtime/serializer" + + _ "k8s.io/kubernetes/pkg/apis/authorization/install" +) + +type GenericWebhook struct { + RestClient *restclient.RESTClient +} + +// New creates a new GenericWebhook from the provided kubeconfig file. +func NewGenericWebhook(kubeConfigFile string, groupVersions []unversioned.GroupVersion) (*GenericWebhook, error) { + for _, groupVersion := range groupVersions { + if !registered.IsEnabledVersion(groupVersion) { + return nil, fmt.Errorf("webhook plugin requires enabling extension resource: %s", groupVersion) + } + } + + loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() + loadingRules.ExplicitPath = kubeConfigFile + loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{}) + + clientConfig, err := loader.ClientConfig() + if err != nil { + return nil, err + } + codec := api.Codecs.LegacyCodec(groupVersions...) + clientConfig.ContentConfig.NegotiatedSerializer = runtimeserializer.NegotiatedSerializerWrapper( + runtime.SerializerInfo{Serializer: codec}, + runtime.StreamSerializerInfo{}, + ) + + restClient, err := restclient.UnversionedRESTClientFor(clientConfig) + if err != nil { + return nil, err + } + + // TODO(ericchiang): Can we ensure remote service is reachable? + + return &GenericWebhook{restClient}, nil +}