mirror of https://github.com/k3s-io/k3s
update admission webhook to accept client config
parent
78ada62c30
commit
0859798e8e
|
@ -70,6 +70,7 @@ go_library(
|
|||
"//vendor/k8s.io/apiserver/pkg/storage/etcd3/preflight:go_default_library",
|
||||
"//vendor/k8s.io/client-go/informers:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
|
||||
"//vendor/k8s.io/kube-aggregator/pkg/apis/apiregistration:go_default_library",
|
||||
"//vendor/k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1:go_default_library",
|
||||
|
|
|
@ -84,6 +84,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/version"
|
||||
"k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/bootstrap"
|
||||
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
_ "k8s.io/kubernetes/pkg/util/reflector/prometheus" // for reflector metric registration
|
||||
_ "k8s.io/kubernetes/pkg/util/workqueue/prometheus" // for workqueue metric registration
|
||||
|
@ -456,12 +457,15 @@ func BuildGenericConfig(s *options.ServerRunOptions, proxyTransport *http.Transp
|
|||
client,
|
||||
sharedInformers,
|
||||
serviceResolver,
|
||||
proxyTransport,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, fmt.Errorf("failed to create admission plugin initializer: %v", err)
|
||||
}
|
||||
|
||||
webhookClientConfig := rest.AnonymousClientConfig(genericConfig.LoopbackClientConfig)
|
||||
if proxyTransport != nil && proxyTransport.Dial != nil {
|
||||
webhookClientConfig.Dial = proxyTransport.Dial
|
||||
}
|
||||
// TODO: this is the wrong cert/key pair.
|
||||
// Given the generic case of webhook admission from a generic apiserver,
|
||||
// this key pair should be signed by the the API server's client CA.
|
||||
|
@ -477,14 +481,17 @@ func BuildGenericConfig(s *options.ServerRunOptions, proxyTransport *http.Transp
|
|||
if err != nil {
|
||||
return nil, nil, nil, nil, nil, fmt.Errorf("failed to read proxy client key file from: %s, err: %v", s.ProxyClientKeyFile, err)
|
||||
}
|
||||
webhookClientConfig.TLSClientConfig.CertData = certBytes
|
||||
webhookClientConfig.TLSClientConfig.KeyData = keyBytes
|
||||
}
|
||||
webhookClientConfig.UserAgent = "kube-apiserver-admission"
|
||||
webhookClientConfig.Timeout = 30 * time.Second
|
||||
|
||||
err = s.Admission.ApplyTo(
|
||||
genericConfig,
|
||||
versionedInformers,
|
||||
certBytes,
|
||||
keyBytes,
|
||||
kubeClientConfig,
|
||||
webhookClientConfig,
|
||||
legacyscheme.Scheme,
|
||||
pluginInitializer)
|
||||
if err != nil {
|
||||
|
@ -494,7 +501,7 @@ func BuildGenericConfig(s *options.ServerRunOptions, proxyTransport *http.Transp
|
|||
}
|
||||
|
||||
// BuildAdmissionPluginInitializer constructs the admission plugin initializer
|
||||
func BuildAdmissionPluginInitializer(s *options.ServerRunOptions, client internalclientset.Interface, sharedInformers informers.SharedInformerFactory, serviceResolver aggregatorapiserver.ServiceResolver, proxyTransport *http.Transport) (admission.PluginInitializer, error) {
|
||||
func BuildAdmissionPluginInitializer(s *options.ServerRunOptions, client internalclientset.Interface, sharedInformers informers.SharedInformerFactory, serviceResolver aggregatorapiserver.ServiceResolver) (admission.PluginInitializer, error) {
|
||||
var cloudConfig []byte
|
||||
|
||||
if s.CloudProvider.CloudConfigFile != "" {
|
||||
|
@ -515,7 +522,6 @@ func BuildAdmissionPluginInitializer(s *options.ServerRunOptions, client interna
|
|||
pluginInitializer := kubeapiserveradmission.NewPluginInitializer(client, sharedInformers, cloudConfig, restMapper, quotaRegistry)
|
||||
|
||||
pluginInitializer = pluginInitializer.SetServiceResolver(serviceResolver)
|
||||
pluginInitializer = pluginInitializer.SetProxyTransport(proxyTransport)
|
||||
|
||||
return pluginInitializer, nil
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@ go_library(
|
|||
"//vendor/k8s.io/apiserver/pkg/server/storage:go_default_library",
|
||||
"//vendor/k8s.io/client-go/informers:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/kube-openapi/pkg/common:go_default_library",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -42,6 +42,7 @@ import (
|
|||
serverstorage "k8s.io/apiserver/pkg/server/storage"
|
||||
clientgoinformers "k8s.io/client-go/informers"
|
||||
clientgoclientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
openapicommon "k8s.io/kube-openapi/pkg/common"
|
||||
federationv1beta1 "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||
"k8s.io/kubernetes/federation/cmd/federation-apiserver/app/options"
|
||||
|
@ -215,9 +216,8 @@ func NonBlockingRun(s *options.ServerRunOptions, stopCh <-chan struct{}) error {
|
|||
err = s.Admission.ApplyTo(
|
||||
genericConfig,
|
||||
versionedInformers,
|
||||
nil,
|
||||
nil,
|
||||
kubeClientConfig,
|
||||
rest.AnonymousClientConfig(kubeClientConfig),
|
||||
legacyscheme.Scheme,
|
||||
pluginInitializer,
|
||||
)
|
||||
|
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
|||
package admission
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
|
@ -71,12 +70,6 @@ type ServiceResolver interface {
|
|||
ResolveEndpoint(namespace, name string) (*url.URL, error)
|
||||
}
|
||||
|
||||
// WantsProxyTransport defines a fuction that accepts a proxy transport for admission
|
||||
// plugins that need to make calls to pods.
|
||||
type WantsProxyTransport interface {
|
||||
SetProxyTransport(proxyTransport *http.Transport)
|
||||
}
|
||||
|
||||
type PluginInitializer struct {
|
||||
internalClient internalclientset.Interface
|
||||
externalClient clientset.Interface
|
||||
|
@ -86,9 +79,6 @@ type PluginInitializer struct {
|
|||
restMapper meta.RESTMapper
|
||||
quotaRegistry quota.Registry
|
||||
serviceResolver ServiceResolver
|
||||
|
||||
// for proving we are apiserver in call-outs
|
||||
proxyTransport *http.Transport
|
||||
}
|
||||
|
||||
var _ admission.PluginInitializer = &PluginInitializer{}
|
||||
|
@ -118,12 +108,6 @@ func (i *PluginInitializer) SetServiceResolver(s ServiceResolver) *PluginInitial
|
|||
return i
|
||||
}
|
||||
|
||||
// SetProxyTransport sets the proxyTransport which is needed by some plugins.
|
||||
func (i *PluginInitializer) SetProxyTransport(proxyTransport *http.Transport) *PluginInitializer {
|
||||
i.proxyTransport = proxyTransport
|
||||
return i
|
||||
}
|
||||
|
||||
// Initialize checks the initialization interfaces implemented by each plugin
|
||||
// and provide the appropriate initialization data
|
||||
func (i *PluginInitializer) Initialize(plugin admission.Interface) {
|
||||
|
@ -150,8 +134,4 @@ func (i *PluginInitializer) Initialize(plugin admission.Interface) {
|
|||
if wants, ok := plugin.(WantsServiceResolver); ok {
|
||||
wants.SetServiceResolver(i.serviceResolver)
|
||||
}
|
||||
|
||||
if wants, ok := plugin.(WantsProxyTransport); ok {
|
||||
wants.SetProxyTransport(i.proxyTransport)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ func newGCPermissionsEnforcement() (*gcPermissionsEnforcement, error) {
|
|||
whiteList: whiteList,
|
||||
}
|
||||
|
||||
genericPluginInitializer, err := initializer.New(nil, nil, fakeAuthorizer{}, nil, nil, nil)
|
||||
genericPluginInitializer, err := initializer.New(nil, nil, fakeAuthorizer{}, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ go_test(
|
|||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
@ -21,10 +21,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
|
@ -105,19 +102,18 @@ type GenericAdmissionWebhook struct {
|
|||
hookSource WebhookSource
|
||||
serviceResolver admissioninit.ServiceResolver
|
||||
negotiatedSerializer runtime.NegotiatedSerializer
|
||||
clientCert []byte
|
||||
clientKey []byte
|
||||
proxyTransport *http.Transport
|
||||
|
||||
restClientConfig *rest.Config
|
||||
}
|
||||
|
||||
var (
|
||||
_ = admissioninit.WantsServiceResolver(&GenericAdmissionWebhook{})
|
||||
_ = genericadmissioninit.WantsClientCert(&GenericAdmissionWebhook{})
|
||||
_ = genericadmissioninit.WantsWebhookRESTClientConfig(&GenericAdmissionWebhook{})
|
||||
_ = genericadmissioninit.WantsExternalKubeClientSet(&GenericAdmissionWebhook{})
|
||||
)
|
||||
|
||||
func (a *GenericAdmissionWebhook) SetProxyTransport(pt *http.Transport) {
|
||||
a.proxyTransport = pt
|
||||
func (a *GenericAdmissionWebhook) SetWebhookRESTClientConfig(in *rest.Config) {
|
||||
a.restClientConfig = in
|
||||
}
|
||||
|
||||
// SetServiceResolver sets a service resolver for the webhook admission plugin.
|
||||
|
@ -137,18 +133,13 @@ func (a *GenericAdmissionWebhook) SetScheme(scheme *runtime.Scheme) {
|
|||
}
|
||||
}
|
||||
|
||||
func (a *GenericAdmissionWebhook) SetClientCert(cert, key []byte) {
|
||||
a.clientCert = cert
|
||||
a.clientKey = key
|
||||
}
|
||||
|
||||
func (a *GenericAdmissionWebhook) SetExternalKubeClientSet(client clientset.Interface) {
|
||||
a.hookSource = configuration.NewExternalAdmissionHookConfigurationManager(client.Admissionregistration().ExternalAdmissionHookConfigurations())
|
||||
}
|
||||
|
||||
func (a *GenericAdmissionWebhook) Validate() error {
|
||||
if a.clientCert == nil || a.clientKey == nil {
|
||||
return fmt.Errorf("the GenericAdmissionWebhook admission plugin requires a client certificate and the private key to be provided")
|
||||
if a.restClientConfig == nil {
|
||||
return fmt.Errorf("the GenericAdmissionWebhook admission plugin requires a restClientConfig to be provided")
|
||||
}
|
||||
if a.hookSource == nil {
|
||||
return fmt.Errorf("the GenericAdmissionWebhook admission plugin requires a Kubernetes client to be provided")
|
||||
|
@ -280,27 +271,12 @@ func (a *GenericAdmissionWebhook) hookClient(h *v1alpha1.ExternalAdmissionHook)
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var dial func(network, addr string) (net.Conn, error)
|
||||
if a.proxyTransport != nil && a.proxyTransport.Dial != nil {
|
||||
dial = a.proxyTransport.Dial
|
||||
}
|
||||
|
||||
// TODO: cache these instead of constructing one each time
|
||||
cfg := &rest.Config{
|
||||
Host: u.Host,
|
||||
APIPath: path.Join(u.Path, h.ClientConfig.URLPath),
|
||||
TLSClientConfig: rest.TLSClientConfig{
|
||||
ServerName: h.ClientConfig.Service.Name + "." + h.ClientConfig.Service.Namespace + ".svc",
|
||||
CAData: h.ClientConfig.CABundle,
|
||||
CertData: a.clientCert,
|
||||
KeyData: a.clientKey,
|
||||
},
|
||||
UserAgent: "kube-apiserver-admission",
|
||||
Timeout: 30 * time.Second,
|
||||
ContentConfig: rest.ContentConfig{
|
||||
NegotiatedSerializer: a.negotiatedSerializer,
|
||||
},
|
||||
Dial: dial,
|
||||
}
|
||||
cfg := rest.CopyConfig(a.restClientConfig)
|
||||
cfg.Host = u.Host
|
||||
cfg.APIPath = path.Join(u.Path, h.ClientConfig.URLPath)
|
||||
cfg.TLSClientConfig.ServerName = h.ClientConfig.Service.Name + "." + h.ClientConfig.Service.Namespace + ".svc"
|
||||
cfg.TLSClientConfig.CAData = h.ClientConfig.CABundle
|
||||
cfg.ContentConfig.NegotiatedSerializer = a.negotiatedSerializer
|
||||
return rest.UnversionedRESTClientFor(cfg)
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import (
|
|||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
|
||||
|
@ -89,8 +90,10 @@ func TestAdmit(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wh.clientCert = clientCert
|
||||
wh.clientKey = clientKey
|
||||
wh.restClientConfig = &rest.Config{}
|
||||
wh.restClientConfig.TLSClientConfig.CAData = caCert
|
||||
wh.restClientConfig.TLSClientConfig.CertData = clientCert
|
||||
wh.restClientConfig.TLSClientConfig.KeyData = clientKey
|
||||
|
||||
// Set up a test object for the call
|
||||
kind := api.Kind("Pod").WithVersion("v1")
|
||||
|
|
|
@ -19,6 +19,7 @@ go_library(
|
|||
"//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
|
||||
"//vendor/k8s.io/client-go/informers:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
@ -22,17 +22,16 @@ import (
|
|||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type pluginInitializer struct {
|
||||
externalClient kubernetes.Interface
|
||||
externalInformers informers.SharedInformerFactory
|
||||
authorizer authorizer.Authorizer
|
||||
// serverIdentifyingClientCert used to provide identity when calling out to admission plugins
|
||||
serverIdentifyingClientCert []byte
|
||||
// serverIdentifyingClientKey private key for the client certificate used when calling out to admission plugins
|
||||
serverIdentifyingClientKey []byte
|
||||
scheme *runtime.Scheme
|
||||
// webhookRESTClientConfig provies a client used to contact webhooks
|
||||
webhookRESTClientConfig *rest.Config
|
||||
scheme *runtime.Scheme
|
||||
}
|
||||
|
||||
// New creates an instance of admission plugins initializer.
|
||||
|
@ -41,17 +40,15 @@ func New(
|
|||
extClientset kubernetes.Interface,
|
||||
extInformers informers.SharedInformerFactory,
|
||||
authz authorizer.Authorizer,
|
||||
serverIdentifyingClientCert,
|
||||
serverIdentifyingClientKey []byte,
|
||||
webhookRESTClientConfig *rest.Config,
|
||||
scheme *runtime.Scheme,
|
||||
) (pluginInitializer, error) {
|
||||
return pluginInitializer{
|
||||
externalClient: extClientset,
|
||||
externalInformers: extInformers,
|
||||
authorizer: authz,
|
||||
serverIdentifyingClientCert: serverIdentifyingClientCert,
|
||||
serverIdentifyingClientKey: serverIdentifyingClientKey,
|
||||
scheme: scheme,
|
||||
externalClient: extClientset,
|
||||
externalInformers: extInformers,
|
||||
authorizer: authz,
|
||||
webhookRESTClientConfig: webhookRESTClientConfig,
|
||||
scheme: scheme,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -70,8 +67,8 @@ func (i pluginInitializer) Initialize(plugin admission.Interface) {
|
|||
wants.SetAuthorizer(i.authorizer)
|
||||
}
|
||||
|
||||
if wants, ok := plugin.(WantsClientCert); ok {
|
||||
wants.SetClientCert(i.serverIdentifyingClientCert, i.serverIdentifyingClientKey)
|
||||
if wants, ok := plugin.(WantsWebhookRESTClientConfig); ok {
|
||||
wants.SetWebhookRESTClientConfig(i.webhookRESTClientConfig)
|
||||
}
|
||||
|
||||
if wants, ok := plugin.(WantsScheme); ok {
|
||||
|
|
|
@ -33,7 +33,7 @@ import (
|
|||
// the WantsScheme interface is implemented by a plugin.
|
||||
func TestWantsScheme(t *testing.T) {
|
||||
scheme := runtime.NewScheme()
|
||||
target, err := initializer.New(nil, nil, nil, nil, nil, scheme)
|
||||
target, err := initializer.New(nil, nil, nil, nil, scheme)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ func TestWantsScheme(t *testing.T) {
|
|||
// TestWantsAuthorizer ensures that the authorizer is injected
|
||||
// when the WantsAuthorizer interface is implemented by a plugin.
|
||||
func TestWantsAuthorizer(t *testing.T) {
|
||||
target, err := initializer.New(nil, nil, &TestAuthorizer{}, nil, nil, nil)
|
||||
target, err := initializer.New(nil, nil, &TestAuthorizer{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ func TestWantsAuthorizer(t *testing.T) {
|
|||
// when the WantsExternalKubeClientSet interface is implemented by a plugin.
|
||||
func TestWantsExternalKubeClientSet(t *testing.T) {
|
||||
cs := &fake.Clientset{}
|
||||
target, err := initializer.New(cs, nil, &TestAuthorizer{}, nil, nil, nil)
|
||||
target, err := initializer.New(cs, nil, &TestAuthorizer{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ func TestWantsExternalKubeClientSet(t *testing.T) {
|
|||
func TestWantsExternalKubeInformerFactory(t *testing.T) {
|
||||
cs := &fake.Clientset{}
|
||||
sf := informers.NewSharedInformerFactory(cs, time.Duration(1)*time.Second)
|
||||
target, err := initializer.New(cs, sf, &TestAuthorizer{}, nil, nil, nil)
|
||||
target, err := initializer.New(cs, sf, &TestAuthorizer{}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -89,20 +89,6 @@ func TestWantsExternalKubeInformerFactory(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestWantsClientCert ensures that the client certificate and key are injected
|
||||
// when the WantsClientCert interface is implemented by a plugin.
|
||||
func TestWantsClientCert(t *testing.T) {
|
||||
target, err := initializer.New(nil, nil, nil, []byte("cert"), []byte("key"), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wantClientCert := &clientCertWanter{}
|
||||
target.Initialize(wantClientCert)
|
||||
if string(wantClientCert.gotCert) != "cert" || string(wantClientCert.gotKey) != "key" {
|
||||
t.Errorf("expected client cert to be initialized, clientCert = %v, clientKey = %v", wantClientCert.gotCert, wantClientCert.gotKey)
|
||||
}
|
||||
}
|
||||
|
||||
// WantExternalKubeInformerFactory is a test stub that fulfills the WantsExternalKubeInformerFactory interface
|
||||
type WantExternalKubeInformerFactory struct {
|
||||
sf informers.SharedInformerFactory
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// WantsExternalKubeClientSet defines a function which sets external ClientSet for admission plugins that need it
|
||||
|
@ -42,10 +43,10 @@ type WantsAuthorizer interface {
|
|||
admission.Validator
|
||||
}
|
||||
|
||||
// WantsClientCert defines a fuction that accepts a cert & key for admission
|
||||
// WantsWebhookRESTClientConfig defines a function that accepts client config for admission
|
||||
// plugins that need to make calls and prove their identity.
|
||||
type WantsClientCert interface {
|
||||
SetClientCert(cert, key []byte)
|
||||
type WantsWebhookRESTClientConfig interface {
|
||||
SetWebhookRESTClientConfig(*rest.Config)
|
||||
admission.Validator
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ func newHandlerForTestWithClock(c clientset.Interface, cacheClock clock.Clock) (
|
|||
if err != nil {
|
||||
return nil, f, err
|
||||
}
|
||||
pluginInitializer, err := kubeadmission.New(c, f, nil, nil, nil, nil)
|
||||
pluginInitializer, err := kubeadmission.New(c, f, nil, nil, nil)
|
||||
if err != nil {
|
||||
return handler, f, err
|
||||
}
|
||||
|
|
|
@ -80,9 +80,8 @@ func (a *AdmissionOptions) AddFlags(fs *pflag.FlagSet) {
|
|||
func (a *AdmissionOptions) ApplyTo(
|
||||
c *server.Config,
|
||||
informers informers.SharedInformerFactory,
|
||||
serverIdentifyingClientCert []byte,
|
||||
serverIdentifyingClientKey []byte,
|
||||
clientConfig *rest.Config,
|
||||
kubeAPIServerClientConfig *rest.Config,
|
||||
webhookClientConfig *rest.Config,
|
||||
scheme *runtime.Scheme,
|
||||
pluginInitializers ...admission.PluginInitializer,
|
||||
) error {
|
||||
|
@ -96,11 +95,11 @@ func (a *AdmissionOptions) ApplyTo(
|
|||
return fmt.Errorf("failed to read plugin config: %v", err)
|
||||
}
|
||||
|
||||
clientset, err := kubernetes.NewForConfig(clientConfig)
|
||||
clientset, err := kubernetes.NewForConfig(kubeAPIServerClientConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
genericInitializer, err := initializer.New(clientset, informers, c.Authorizer, serverIdentifyingClientCert, serverIdentifyingClientKey, scheme)
|
||||
genericInitializer, err := initializer.New(clientset, informers, c.Authorizer, webhookClientConfig, scheme)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -420,5 +420,45 @@ func AnonymousClientConfig(config *Config) *Config {
|
|||
QPS: config.QPS,
|
||||
Burst: config.Burst,
|
||||
Timeout: config.Timeout,
|
||||
Dial: config.Dial,
|
||||
}
|
||||
}
|
||||
|
||||
// CopyConfig returns a copy of the given config
|
||||
func CopyConfig(config *Config) *Config {
|
||||
return &Config{
|
||||
Host: config.Host,
|
||||
APIPath: config.APIPath,
|
||||
Prefix: config.Prefix,
|
||||
ContentConfig: config.ContentConfig,
|
||||
Username: config.Username,
|
||||
Password: config.Password,
|
||||
BearerToken: config.BearerToken,
|
||||
CacheDir: config.CacheDir,
|
||||
Impersonate: ImpersonationConfig{
|
||||
Groups: config.Impersonate.Groups,
|
||||
Extra: config.Impersonate.Extra,
|
||||
UserName: config.Impersonate.UserName,
|
||||
},
|
||||
AuthProvider: config.AuthProvider,
|
||||
AuthConfigPersister: config.AuthConfigPersister,
|
||||
TLSClientConfig: TLSClientConfig{
|
||||
Insecure: config.TLSClientConfig.Insecure,
|
||||
ServerName: config.TLSClientConfig.ServerName,
|
||||
CertFile: config.TLSClientConfig.CertFile,
|
||||
KeyFile: config.TLSClientConfig.KeyFile,
|
||||
CAFile: config.TLSClientConfig.CAFile,
|
||||
CertData: config.TLSClientConfig.CertData,
|
||||
KeyData: config.TLSClientConfig.KeyData,
|
||||
CAData: config.TLSClientConfig.CAData,
|
||||
},
|
||||
UserAgent: config.UserAgent,
|
||||
Transport: config.Transport,
|
||||
WrapTransport: config.WrapTransport,
|
||||
QPS: config.QPS,
|
||||
Burst: config.Burst,
|
||||
RateLimiter: config.RateLimiter,
|
||||
Timeout: config.Timeout,
|
||||
Dial: config.Dial,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ import (
|
|||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
|
||||
"errors"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -206,6 +208,19 @@ func (n *fakeNegotiatedSerializer) DecoderToVersion(serializer runtime.Decoder,
|
|||
return &fakeCodec{}
|
||||
}
|
||||
|
||||
var fakeDialFunc = func(network, addr string) (net.Conn, error) {
|
||||
return nil, fakeDialerError
|
||||
}
|
||||
var fakeDialerError = errors.New("fakedialer")
|
||||
|
||||
type fakeAuthProviderConfigPersister struct{}
|
||||
|
||||
func (fakeAuthProviderConfigPersister) Persist(map[string]string) error {
|
||||
return fakeAuthProviderConfigPersisterError
|
||||
}
|
||||
|
||||
var fakeAuthProviderConfigPersisterError = errors.New("fakeAuthProviderConfigPersisterError")
|
||||
|
||||
func TestAnonymousConfig(t *testing.T) {
|
||||
f := fuzz.New().NilChance(0.0).NumElements(1, 1)
|
||||
f.Funcs(
|
||||
|
@ -268,9 +283,94 @@ func TestAnonymousConfig(t *testing.T) {
|
|||
actual.WrapTransport = nil
|
||||
expected.WrapTransport = nil
|
||||
}
|
||||
if actual.Dial != nil {
|
||||
_, actualError := actual.Dial("", "")
|
||||
_, expectedError := actual.Dial("", "")
|
||||
if !reflect.DeepEqual(expectedError, actualError) {
|
||||
t.Fatalf("CopyConfig dropped the Dial field")
|
||||
}
|
||||
} else {
|
||||
actual.Dial = nil
|
||||
expected.Dial = nil
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(*actual, expected) {
|
||||
t.Fatalf("AnonymousClientConfig dropped unexpected fields, identify whether they are security related or not: %s", diff.ObjectGoPrintDiff(expected, actual))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyConfig(t *testing.T) {
|
||||
f := fuzz.New().NilChance(0.0).NumElements(1, 1)
|
||||
f.Funcs(
|
||||
func(r *runtime.Codec, f fuzz.Continue) {
|
||||
codec := &fakeCodec{}
|
||||
f.Fuzz(codec)
|
||||
*r = codec
|
||||
},
|
||||
func(r *http.RoundTripper, f fuzz.Continue) {
|
||||
roundTripper := &fakeRoundTripper{}
|
||||
f.Fuzz(roundTripper)
|
||||
*r = roundTripper
|
||||
},
|
||||
func(fn *func(http.RoundTripper) http.RoundTripper, f fuzz.Continue) {
|
||||
*fn = fakeWrapperFunc
|
||||
},
|
||||
func(r *runtime.NegotiatedSerializer, f fuzz.Continue) {
|
||||
serializer := &fakeNegotiatedSerializer{}
|
||||
f.Fuzz(serializer)
|
||||
*r = serializer
|
||||
},
|
||||
func(r *flowcontrol.RateLimiter, f fuzz.Continue) {
|
||||
limiter := &fakeLimiter{}
|
||||
f.Fuzz(limiter)
|
||||
*r = limiter
|
||||
},
|
||||
func(r *AuthProviderConfigPersister, f fuzz.Continue) {
|
||||
*r = fakeAuthProviderConfigPersister{}
|
||||
},
|
||||
func(r *func(network, addr string) (net.Conn, error), f fuzz.Continue) {
|
||||
*r = fakeDialFunc
|
||||
},
|
||||
)
|
||||
for i := 0; i < 20; i++ {
|
||||
original := &Config{}
|
||||
f.Fuzz(original)
|
||||
actual := CopyConfig(original)
|
||||
expected := *original
|
||||
|
||||
// this is the list of known risky fields, add to this list if a new field
|
||||
// is added to Config, update CopyConfig to preserve the field otherwise.
|
||||
|
||||
// The DeepEqual cannot handle the func comparison, so we just verify if the
|
||||
// function return the expected object.
|
||||
if actual.WrapTransport == nil || !reflect.DeepEqual(expected.WrapTransport(nil), &fakeRoundTripper{}) {
|
||||
t.Fatalf("CopyConfig dropped the WrapTransport field")
|
||||
} else {
|
||||
actual.WrapTransport = nil
|
||||
expected.WrapTransport = nil
|
||||
}
|
||||
if actual.Dial != nil {
|
||||
_, actualError := actual.Dial("", "")
|
||||
_, expectedError := actual.Dial("", "")
|
||||
if !reflect.DeepEqual(expectedError, actualError) {
|
||||
t.Fatalf("CopyConfig dropped the Dial field")
|
||||
}
|
||||
}
|
||||
actual.Dial = nil
|
||||
expected.Dial = nil
|
||||
if actual.AuthConfigPersister != nil {
|
||||
actualError := actual.AuthConfigPersister.Persist(nil)
|
||||
expectedError := actual.AuthConfigPersister.Persist(nil)
|
||||
if !reflect.DeepEqual(expectedError, actualError) {
|
||||
t.Fatalf("CopyConfig dropped the Dial field")
|
||||
}
|
||||
}
|
||||
actual.AuthConfigPersister = nil
|
||||
expected.AuthConfigPersister = nil
|
||||
|
||||
if !reflect.DeepEqual(*actual, expected) {
|
||||
t.Fatalf("CopyConfig dropped unexpected fields, identify whether they are security related or not: %s", diff.ObjectReflectDiff(expected, *actual))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ func (o WardleServerOptions) Config() (*apiserver.Config, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := o.Admission.ApplyTo(&serverConfig.Config, serverConfig.SharedInformerFactory, nil, nil, serverConfig.ClientConfig, apiserver.Scheme, admissionInitializer); err != nil {
|
||||
if err := o.Admission.ApplyTo(&serverConfig.Config, serverConfig.SharedInformerFactory, serverConfig.ClientConfig, serverConfig.ClientConfig, apiserver.Scheme, admissionInitializer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue