From d318e52ffe0ba156a96cb5507026de6827d543ca Mon Sep 17 00:00:00 2001 From: Jefftree Date: Tue, 3 Dec 2019 15:20:49 -0800 Subject: [PATCH 1/4] authentication webhook via network proxy --- cmd/kube-apiserver/app/server.go | 8 ++++++-- pkg/kubeapiserver/authenticator/BUILD | 1 + pkg/kubeapiserver/authenticator/config.go | 16 +++++++++++++--- plugin/pkg/admission/imagepolicy/admission.go | 2 +- .../apiserver/pkg/util/webhook/webhook.go | 17 ++++++++++++++--- .../apiserver/pkg/util/webhook/webhook_test.go | 10 +++++----- .../plugin/pkg/audit/webhook/webhook.go | 2 +- .../pkg/authenticator/token/webhook/BUILD | 1 + .../pkg/authenticator/token/webhook/webhook.go | 11 ++++++----- .../token/webhook/webhook_v1_test.go | 2 +- .../token/webhook/webhook_v1beta1_test.go | 2 +- .../plugin/pkg/authorizer/webhook/webhook.go | 4 ++-- test/integration/auth/auth_test.go | 2 +- 13 files changed, 53 insertions(+), 25 deletions(-) diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index 6c58e076515..3cb01639651 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -498,7 +498,7 @@ func buildGenericConfig( } versionedInformers = clientgoinformers.NewSharedInformerFactory(clientgoExternalClient, 10*time.Minute) - genericConfig.Authentication.Authenticator, genericConfig.OpenAPIConfig.SecurityDefinitions, err = BuildAuthenticator(s, clientgoExternalClient, versionedInformers) + genericConfig.Authentication.Authenticator, genericConfig.OpenAPIConfig.SecurityDefinitions, err = BuildAuthenticator(s, genericConfig, clientgoExternalClient, versionedInformers) if err != nil { lastErr = fmt.Errorf("invalid authentication config: %v", err) return @@ -560,7 +560,7 @@ func buildGenericConfig( } // BuildAuthenticator constructs the authenticator -func BuildAuthenticator(s *options.ServerRunOptions, extclient clientgoclientset.Interface, versionedInformer clientgoinformers.SharedInformerFactory) (authenticator.Request, *spec.SecurityDefinitions, error) { +func BuildAuthenticator(s *options.ServerRunOptions, c *genericapiserver.Config, extclient clientgoclientset.Interface, versionedInformer clientgoinformers.SharedInformerFactory) (authenticator.Request, *spec.SecurityDefinitions, error) { authenticatorConfig, err := s.Authentication.ToAuthenticationConfig() if err != nil { return nil, nil, err @@ -577,6 +577,10 @@ func BuildAuthenticator(s *options.ServerRunOptions, extclient clientgoclientset versionedInformer.Core().V1().Secrets().Lister().Secrets(v1.NamespaceSystem), ) + if c.EgressSelector != nil { + authenticatorConfig.EgressLookup = c.EgressSelector.Lookup + } + return authenticatorConfig.New() } diff --git a/pkg/kubeapiserver/authenticator/BUILD b/pkg/kubeapiserver/authenticator/BUILD index 68c7c30d862..9f537e18760 100644 --- a/pkg/kubeapiserver/authenticator/BUILD +++ b/pkg/kubeapiserver/authenticator/BUILD @@ -25,6 +25,7 @@ go_library( "//staging/src/k8s.io/apiserver/pkg/authentication/token/tokenfile:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authentication/token/union:go_default_library", "//staging/src/k8s.io/apiserver/pkg/server/dynamiccertificates:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/server/egressselector:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", "//staging/src/k8s.io/apiserver/plugin/pkg/authenticator/password/passwordfile:go_default_library", "//staging/src/k8s.io/apiserver/plugin/pkg/authenticator/request/basicauth:go_default_library", diff --git a/pkg/kubeapiserver/authenticator/config.go b/pkg/kubeapiserver/authenticator/config.go index ad541fc8a11..daf1894ad82 100644 --- a/pkg/kubeapiserver/authenticator/config.go +++ b/pkg/kubeapiserver/authenticator/config.go @@ -34,6 +34,7 @@ import ( "k8s.io/apiserver/pkg/authentication/token/tokenfile" tokenunion "k8s.io/apiserver/pkg/authentication/token/union" "k8s.io/apiserver/pkg/server/dynamiccertificates" + "k8s.io/apiserver/pkg/server/egressselector" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/apiserver/plugin/pkg/authenticator/password/passwordfile" "k8s.io/apiserver/plugin/pkg/authenticator/request/basicauth" @@ -83,6 +84,9 @@ type Config struct { // Generally this is the CA bundle file used to authenticate client certificates // If this value is nil, then mutual TLS is disabled. ClientCAContentProvider dynamiccertificates.CAContentProvider + + // Lookup will give us a dialer if the egress selector is configured for it + EgressLookup egressselector.Lookup } // New returns an authenticator.Request or an error that supports the standard @@ -179,10 +183,11 @@ func (config Config) New() (authenticator.Request, *spec.SecurityDefinitions, er tokenAuthenticators = append(tokenAuthenticators, authenticator.WrapAudienceAgnosticToken(config.APIAudiences, oidcAuth)) } if len(config.WebhookTokenAuthnConfigFile) > 0 { - webhookTokenAuth, err := newWebhookTokenAuthenticator(config.WebhookTokenAuthnConfigFile, config.WebhookTokenAuthnVersion, config.WebhookTokenAuthnCacheTTL, config.APIAudiences) + webhookTokenAuth, err := newWebhookTokenAuthenticator(config) if err != nil { return nil, nil, err } + tokenAuthenticators = append(tokenAuthenticators, webhookTokenAuth) } @@ -305,8 +310,13 @@ func newServiceAccountAuthenticator(iss string, keyfiles []string, apiAudiences return tokenAuthenticator, nil } -func newWebhookTokenAuthenticator(webhookConfigFile string, version string, ttl time.Duration, implicitAuds authenticator.Audiences) (authenticator.Token, error) { - webhookTokenAuthenticator, err := webhook.New(webhookConfigFile, version, implicitAuds) +func newWebhookTokenAuthenticator(config Config) (authenticator.Token, error) { + webhookConfigFile := config.WebhookTokenAuthnConfigFile + version := config.WebhookTokenAuthnVersion + ttl := config.WebhookTokenAuthnCacheTTL + implicitAuds := config.APIAudiences + + webhookTokenAuthenticator, err := webhook.New(webhookConfigFile, version, implicitAuds, config.EgressLookup) if err != nil { return nil, err } diff --git a/plugin/pkg/admission/imagepolicy/admission.go b/plugin/pkg/admission/imagepolicy/admission.go index 50921fc8cee..ddd06b43b56 100644 --- a/plugin/pkg/admission/imagepolicy/admission.go +++ b/plugin/pkg/admission/imagepolicy/admission.go @@ -261,7 +261,7 @@ func NewImagePolicyWebhook(configFile io.Reader) (*Plugin, error) { return nil, err } - gw, err := webhook.NewGenericWebhook(legacyscheme.Scheme, legacyscheme.Codecs, whConfig.KubeConfigFile, groupVersions, whConfig.RetryBackoff) + gw, err := webhook.NewGenericWebhook(legacyscheme.Scheme, legacyscheme.Codecs, whConfig.KubeConfigFile, groupVersions, whConfig.RetryBackoff, nil) if err != nil { return nil, err } diff --git a/staging/src/k8s.io/apiserver/pkg/util/webhook/webhook.go b/staging/src/k8s.io/apiserver/pkg/util/webhook/webhook.go index d2c6e2273f7..8975129b0b1 100644 --- a/staging/src/k8s.io/apiserver/pkg/util/webhook/webhook.go +++ b/staging/src/k8s.io/apiserver/pkg/util/webhook/webhook.go @@ -27,7 +27,9 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/util/net" + utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/apiserver/pkg/server/egressselector" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" ) @@ -61,11 +63,11 @@ func DefaultShouldRetry(err error) bool { } // NewGenericWebhook creates a new GenericWebhook from the provided kubeconfig file. -func NewGenericWebhook(scheme *runtime.Scheme, codecFactory serializer.CodecFactory, kubeConfigFile string, groupVersions []schema.GroupVersion, initialBackoff time.Duration) (*GenericWebhook, error) { - return newGenericWebhook(scheme, codecFactory, kubeConfigFile, groupVersions, initialBackoff, defaultRequestTimeout) +func NewGenericWebhook(scheme *runtime.Scheme, codecFactory serializer.CodecFactory, kubeConfigFile string, groupVersions []schema.GroupVersion, initialBackoff time.Duration, egressLookup egressselector.Lookup) (*GenericWebhook, error) { + return newGenericWebhook(scheme, codecFactory, kubeConfigFile, groupVersions, initialBackoff, defaultRequestTimeout, egressLookup) } -func newGenericWebhook(scheme *runtime.Scheme, codecFactory serializer.CodecFactory, kubeConfigFile string, groupVersions []schema.GroupVersion, initialBackoff, requestTimeout time.Duration) (*GenericWebhook, error) { +func newGenericWebhook(scheme *runtime.Scheme, codecFactory serializer.CodecFactory, kubeConfigFile string, groupVersions []schema.GroupVersion, initialBackoff, requestTimeout time.Duration, egressLookup egressselector.Lookup) (*GenericWebhook, error) { for _, groupVersion := range groupVersions { if !scheme.IsVersionRegistered(groupVersion) { return nil, fmt.Errorf("webhook plugin requires enabling extension resource: %s", groupVersion) @@ -94,6 +96,15 @@ func newGenericWebhook(scheme *runtime.Scheme, codecFactory serializer.CodecFact codec := codecFactory.LegacyCodec(groupVersions...) clientConfig.ContentConfig.NegotiatedSerializer = serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: codec}) + if egressLookup != nil { + networkContext := egressselector.Master.AsNetworkContext() + var egressDialer utilnet.DialFunc + egressDialer, err = egressLookup(networkContext) + if err != nil { + return nil, err + } + clientConfig.Dial = egressDialer + } restClient, err := rest.UnversionedRESTClientFor(clientConfig) if err != nil { diff --git a/staging/src/k8s.io/apiserver/pkg/util/webhook/webhook_test.go b/staging/src/k8s.io/apiserver/pkg/util/webhook/webhook_test.go index 7fda708749d..b70d146e838 100644 --- a/staging/src/k8s.io/apiserver/pkg/util/webhook/webhook_test.go +++ b/staging/src/k8s.io/apiserver/pkg/util/webhook/webhook_test.go @@ -259,7 +259,7 @@ func TestKubeConfigFile(t *testing.T) { if err == nil { defer os.Remove(kubeConfigFile) - _, err = NewGenericWebhook(runtime.NewScheme(), scheme.Codecs, kubeConfigFile, groupVersions, retryBackoff) + _, err = NewGenericWebhook(runtime.NewScheme(), scheme.Codecs, kubeConfigFile, groupVersions, retryBackoff, nil) } return err @@ -282,7 +282,7 @@ func TestKubeConfigFile(t *testing.T) { // TestMissingKubeConfigFile ensures that a kube config path to a missing file is handled properly func TestMissingKubeConfigFile(t *testing.T) { kubeConfigPath := "/some/missing/path" - _, err := NewGenericWebhook(runtime.NewScheme(), scheme.Codecs, kubeConfigPath, groupVersions, retryBackoff) + _, err := NewGenericWebhook(runtime.NewScheme(), scheme.Codecs, kubeConfigPath, groupVersions, retryBackoff, nil) if err == nil { t.Errorf("creating the webhook should had failed") @@ -394,7 +394,7 @@ func TestTLSConfig(t *testing.T) { defer os.Remove(configFile) - wh, err := NewGenericWebhook(runtime.NewScheme(), scheme.Codecs, configFile, groupVersions, retryBackoff) + wh, err := NewGenericWebhook(runtime.NewScheme(), scheme.Codecs, configFile, groupVersions, retryBackoff, nil) if err == nil { err = wh.RestClient.Get().Do(context.TODO()).Error() @@ -459,7 +459,7 @@ func TestRequestTimeout(t *testing.T) { var requestTimeout = 10 * time.Millisecond - wh, err := newGenericWebhook(runtime.NewScheme(), scheme.Codecs, configFile, groupVersions, retryBackoff, requestTimeout) + wh, err := newGenericWebhook(runtime.NewScheme(), scheme.Codecs, configFile, groupVersions, retryBackoff, requestTimeout, nil) if err != nil { t.Fatalf("failed to create the webhook: %v", err) } @@ -545,7 +545,7 @@ func TestWithExponentialBackoff(t *testing.T) { defer os.Remove(configFile) - wh, err := NewGenericWebhook(runtime.NewScheme(), scheme.Codecs, configFile, groupVersions, retryBackoff) + wh, err := NewGenericWebhook(runtime.NewScheme(), scheme.Codecs, configFile, groupVersions, retryBackoff, nil) if err != nil { t.Fatalf("failed to create the webhook: %v", err) diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/audit/webhook/webhook.go b/staging/src/k8s.io/apiserver/plugin/pkg/audit/webhook/webhook.go index f73c1fd5626..861ec72dd3e 100644 --- a/staging/src/k8s.io/apiserver/plugin/pkg/audit/webhook/webhook.go +++ b/staging/src/k8s.io/apiserver/plugin/pkg/audit/webhook/webhook.go @@ -62,7 +62,7 @@ func retryOnError(err error) bool { func loadWebhook(configFile string, groupVersion schema.GroupVersion, initialBackoff time.Duration) (*webhook.GenericWebhook, error) { w, err := webhook.NewGenericWebhook(audit.Scheme, audit.Codecs, configFile, - []schema.GroupVersion{groupVersion}, initialBackoff) + []schema.GroupVersion{groupVersion}, initialBackoff, nil) w.ShouldRetry = retryOnError return w, err } diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/BUILD b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/BUILD index dc2839f18d2..9159bcb5f89 100644 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/BUILD +++ b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/BUILD @@ -41,6 +41,7 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/server/egressselector:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/webhook:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/typed/authentication/v1:go_default_library", diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/webhook.go b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/webhook.go index 7410d1959ed..1d5a90f6b8e 100644 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/webhook.go +++ b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/webhook.go @@ -30,6 +30,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/authentication/user" + "k8s.io/apiserver/pkg/server/egressselector" "k8s.io/apiserver/pkg/util/webhook" "k8s.io/client-go/kubernetes/scheme" authenticationv1client "k8s.io/client-go/kubernetes/typed/authentication/v1" @@ -63,8 +64,8 @@ func NewFromInterface(tokenReview authenticationv1client.TokenReviewInterface, i // file. It is recommend to wrap this authenticator with the token cache // authenticator implemented in // k8s.io/apiserver/pkg/authentication/token/cache. -func New(kubeConfigFile string, version string, implicitAuds authenticator.Audiences) (*WebhookTokenAuthenticator, error) { - tokenReview, err := tokenReviewInterfaceFromKubeconfig(kubeConfigFile, version) +func New(kubeConfigFile string, version string, implicitAuds authenticator.Audiences, egressLookup egressselector.Lookup) (*WebhookTokenAuthenticator, error) { + tokenReview, err := tokenReviewInterfaceFromKubeconfig(kubeConfigFile, version, egressLookup) if err != nil { return nil, err } @@ -153,7 +154,7 @@ func (w *WebhookTokenAuthenticator) AuthenticateToken(ctx context.Context, token // tokenReviewInterfaceFromKubeconfig builds a client from the specified kubeconfig file, // and returns a TokenReviewInterface that uses that client. Note that the client submits TokenReview // requests to the exact path specified in the kubeconfig file, so arbitrary non-API servers can be targeted. -func tokenReviewInterfaceFromKubeconfig(kubeConfigFile string, version string) (tokenReviewer, error) { +func tokenReviewInterfaceFromKubeconfig(kubeConfigFile string, version string, egressLookup egressselector.Lookup) (tokenReviewer, error) { localScheme := runtime.NewScheme() if err := scheme.AddToScheme(localScheme); err != nil { return nil, err @@ -165,7 +166,7 @@ func tokenReviewInterfaceFromKubeconfig(kubeConfigFile string, version string) ( if err := localScheme.SetVersionPriority(groupVersions...); err != nil { return nil, err } - gw, err := webhook.NewGenericWebhook(localScheme, scheme.Codecs, kubeConfigFile, groupVersions, 0) + gw, err := webhook.NewGenericWebhook(localScheme, scheme.Codecs, kubeConfigFile, groupVersions, 0, egressLookup) if err != nil { return nil, err } @@ -176,7 +177,7 @@ func tokenReviewInterfaceFromKubeconfig(kubeConfigFile string, version string) ( if err := localScheme.SetVersionPriority(groupVersions...); err != nil { return nil, err } - gw, err := webhook.NewGenericWebhook(localScheme, scheme.Codecs, kubeConfigFile, groupVersions, 0) + gw, err := webhook.NewGenericWebhook(localScheme, scheme.Codecs, kubeConfigFile, groupVersions, 0, egressLookup) if err != nil { return nil, err } diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/webhook_v1_test.go b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/webhook_v1_test.go index 884317242cd..e9bf2a36d7b 100644 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/webhook_v1_test.go +++ b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/webhook_v1_test.go @@ -193,7 +193,7 @@ func newV1TokenAuthenticator(serverURL string, clientCert, clientKey, ca []byte, return nil, err } - c, err := tokenReviewInterfaceFromKubeconfig(p, "v1") + c, err := tokenReviewInterfaceFromKubeconfig(p, "v1", nil) if err != nil { return nil, err } diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/webhook_v1beta1_test.go b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/webhook_v1beta1_test.go index 514fd9df3f3..e5ea01baee9 100644 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/webhook_v1beta1_test.go +++ b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/webhook_v1beta1_test.go @@ -195,7 +195,7 @@ func newV1beta1TokenAuthenticator(serverURL string, clientCert, clientKey, ca [] return nil, err } - c, err := tokenReviewInterfaceFromKubeconfig(p, "v1beta1") + c, err := tokenReviewInterfaceFromKubeconfig(p, "v1beta1", nil) if err != nil { return nil, err } diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook.go b/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook.go index cc8b5e78bc6..b496b6c5874 100644 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook.go +++ b/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook.go @@ -257,7 +257,7 @@ func subjectAccessReviewInterfaceFromKubeconfig(kubeConfigFile string, version s if err := localScheme.SetVersionPriority(groupVersions...); err != nil { return nil, err } - gw, err := webhook.NewGenericWebhook(localScheme, scheme.Codecs, kubeConfigFile, groupVersions, 0) + gw, err := webhook.NewGenericWebhook(localScheme, scheme.Codecs, kubeConfigFile, groupVersions, 0, nil) if err != nil { return nil, err } @@ -268,7 +268,7 @@ func subjectAccessReviewInterfaceFromKubeconfig(kubeConfigFile string, version s if err := localScheme.SetVersionPriority(groupVersions...); err != nil { return nil, err } - gw, err := webhook.NewGenericWebhook(localScheme, scheme.Codecs, kubeConfigFile, groupVersions, 0) + gw, err := webhook.NewGenericWebhook(localScheme, scheme.Codecs, kubeConfigFile, groupVersions, 0, nil) if err != nil { return nil, err } diff --git a/test/integration/auth/auth_test.go b/test/integration/auth/auth_test.go index 3ecfab3a7fd..49418001e29 100644 --- a/test/integration/auth/auth_test.go +++ b/test/integration/auth/auth_test.go @@ -85,7 +85,7 @@ func getTestWebhookTokenAuth(serverURL string) (authenticator.Request, error) { if err := json.NewEncoder(kubecfgFile).Encode(config); err != nil { return nil, err } - webhookTokenAuth, err := webhook.New(kubecfgFile.Name(), "v1beta1", nil) + webhookTokenAuth, err := webhook.New(kubecfgFile.Name(), "v1beta1", nil, nil) if err != nil { return nil, err } From 1b38199ea8b220be0b645af8a4cbdef4c87ce7fc Mon Sep 17 00:00:00 2001 From: Jefftree Date: Thu, 5 Dec 2019 17:28:59 -0800 Subject: [PATCH 2/4] pass Dialer instead of egressselector to webhooks --- cmd/kube-apiserver/app/server.go | 25 +++++++++++---- pkg/kubeapiserver/authenticator/BUILD | 2 +- pkg/kubeapiserver/authenticator/config.go | 15 +++------ pkg/kubeapiserver/authorizer/BUILD | 1 + pkg/kubeapiserver/authorizer/config.go | 7 ++++- .../k8s.io/apiserver/pkg/util/webhook/BUILD | 1 - .../apiserver/pkg/util/webhook/webhook.go | 18 ++++------- .../pkg/authenticator/token/webhook/BUILD | 2 +- .../authenticator/token/webhook/webhook.go | 12 +++---- .../plugin/pkg/authorizer/webhook/BUILD | 1 + .../plugin/pkg/authorizer/webhook/webhook.go | 11 ++++--- .../pkg/authorizer/webhook/webhook_v1_test.go | 4 +-- .../webhook/webhook_v1beta1_test.go | 4 +-- test/integration/auth/BUILD | 1 + test/integration/auth/auth_test.go | 31 +++++++++++++++++-- 15 files changed, 85 insertions(+), 50 deletions(-) diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index 3cb01639651..a278e3ad3b4 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -498,13 +498,13 @@ func buildGenericConfig( } versionedInformers = clientgoinformers.NewSharedInformerFactory(clientgoExternalClient, 10*time.Minute) - genericConfig.Authentication.Authenticator, genericConfig.OpenAPIConfig.SecurityDefinitions, err = BuildAuthenticator(s, genericConfig, clientgoExternalClient, versionedInformers) + genericConfig.Authentication.Authenticator, genericConfig.OpenAPIConfig.SecurityDefinitions, err = BuildAuthenticator(s, genericConfig.EgressSelector, clientgoExternalClient, versionedInformers) if err != nil { lastErr = fmt.Errorf("invalid authentication config: %v", err) return } - genericConfig.Authorization.Authorizer, genericConfig.RuleResolver, err = BuildAuthorizer(s, versionedInformers) + genericConfig.Authorization.Authorizer, genericConfig.RuleResolver, err = BuildAuthorizer(s, genericConfig.EgressSelector, versionedInformers) if err != nil { lastErr = fmt.Errorf("invalid authorization config: %v", err) return @@ -560,7 +560,7 @@ func buildGenericConfig( } // BuildAuthenticator constructs the authenticator -func BuildAuthenticator(s *options.ServerRunOptions, c *genericapiserver.Config, extclient clientgoclientset.Interface, versionedInformer clientgoinformers.SharedInformerFactory) (authenticator.Request, *spec.SecurityDefinitions, error) { +func BuildAuthenticator(s *options.ServerRunOptions, EgressSelector *egressselector.EgressSelector, extclient clientgoclientset.Interface, versionedInformer clientgoinformers.SharedInformerFactory) (authenticator.Request, *spec.SecurityDefinitions, error) { authenticatorConfig, err := s.Authentication.ToAuthenticationConfig() if err != nil { return nil, nil, err @@ -577,16 +577,29 @@ func BuildAuthenticator(s *options.ServerRunOptions, c *genericapiserver.Config, versionedInformer.Core().V1().Secrets().Lister().Secrets(v1.NamespaceSystem), ) - if c.EgressSelector != nil { - authenticatorConfig.EgressLookup = c.EgressSelector.Lookup + if EgressSelector != nil { + egressDialer, err := EgressSelector.Lookup(egressselector.Master.AsNetworkContext()) + if err != nil { + return nil, nil, err + } + authenticatorConfig.CustomDial = egressDialer } return authenticatorConfig.New() } // BuildAuthorizer constructs the authorizer -func BuildAuthorizer(s *options.ServerRunOptions, versionedInformers clientgoinformers.SharedInformerFactory) (authorizer.Authorizer, authorizer.RuleResolver, error) { +func BuildAuthorizer(s *options.ServerRunOptions, EgressSelector *egressselector.EgressSelector, versionedInformers clientgoinformers.SharedInformerFactory) (authorizer.Authorizer, authorizer.RuleResolver, error) { authorizationConfig := s.Authorization.ToAuthorizationConfig(versionedInformers) + + if EgressSelector != nil { + egressDialer, err := EgressSelector.Lookup(egressselector.Master.AsNetworkContext()) + if err != nil { + return nil, nil, err + } + authorizationConfig.CustomDial = egressDialer + } + return authorizationConfig.New() } diff --git a/pkg/kubeapiserver/authenticator/BUILD b/pkg/kubeapiserver/authenticator/BUILD index 9f537e18760..ba70ad6e388 100644 --- a/pkg/kubeapiserver/authenticator/BUILD +++ b/pkg/kubeapiserver/authenticator/BUILD @@ -12,6 +12,7 @@ go_library( deps = [ "//pkg/features:go_default_library", "//pkg/serviceaccount:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authentication/authenticatorfactory:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authentication/group:go_default_library", @@ -25,7 +26,6 @@ go_library( "//staging/src/k8s.io/apiserver/pkg/authentication/token/tokenfile:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authentication/token/union:go_default_library", "//staging/src/k8s.io/apiserver/pkg/server/dynamiccertificates:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/server/egressselector:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", "//staging/src/k8s.io/apiserver/plugin/pkg/authenticator/password/passwordfile:go_default_library", "//staging/src/k8s.io/apiserver/plugin/pkg/authenticator/request/basicauth:go_default_library", diff --git a/pkg/kubeapiserver/authenticator/config.go b/pkg/kubeapiserver/authenticator/config.go index daf1894ad82..c54c64651cd 100644 --- a/pkg/kubeapiserver/authenticator/config.go +++ b/pkg/kubeapiserver/authenticator/config.go @@ -21,6 +21,7 @@ import ( "github.com/go-openapi/spec" + utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/authentication/authenticatorfactory" "k8s.io/apiserver/pkg/authentication/group" @@ -34,7 +35,6 @@ import ( "k8s.io/apiserver/pkg/authentication/token/tokenfile" tokenunion "k8s.io/apiserver/pkg/authentication/token/union" "k8s.io/apiserver/pkg/server/dynamiccertificates" - "k8s.io/apiserver/pkg/server/egressselector" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/apiserver/plugin/pkg/authenticator/password/passwordfile" "k8s.io/apiserver/plugin/pkg/authenticator/request/basicauth" @@ -85,8 +85,8 @@ type Config struct { // If this value is nil, then mutual TLS is disabled. ClientCAContentProvider dynamiccertificates.CAContentProvider - // Lookup will give us a dialer if the egress selector is configured for it - EgressLookup egressselector.Lookup + // Optional field, custom dial function used to connect to webhook + CustomDial utilnet.DialFunc } // New returns an authenticator.Request or an error that supports the standard @@ -311,15 +311,10 @@ func newServiceAccountAuthenticator(iss string, keyfiles []string, apiAudiences } func newWebhookTokenAuthenticator(config Config) (authenticator.Token, error) { - webhookConfigFile := config.WebhookTokenAuthnConfigFile - version := config.WebhookTokenAuthnVersion - ttl := config.WebhookTokenAuthnCacheTTL - implicitAuds := config.APIAudiences - - webhookTokenAuthenticator, err := webhook.New(webhookConfigFile, version, implicitAuds, config.EgressLookup) + webhookTokenAuthenticator, err := webhook.New(config.WebhookTokenAuthnConfigFile, config.WebhookTokenAuthnVersion, config.APIAudiences, config.CustomDial) if err != nil { return nil, err } - return tokencache.New(webhookTokenAuthenticator, false, ttl, ttl), nil + return tokencache.New(webhookTokenAuthenticator, false, config.WebhookTokenAuthnCacheTTL, config.WebhookTokenAuthnCacheTTL), nil } diff --git a/pkg/kubeapiserver/authorizer/BUILD b/pkg/kubeapiserver/authorizer/BUILD index 129eacedfca..06e5735e1a1 100644 --- a/pkg/kubeapiserver/authorizer/BUILD +++ b/pkg/kubeapiserver/authorizer/BUILD @@ -16,6 +16,7 @@ go_library( "//plugin/pkg/auth/authorizer/node:go_default_library", "//plugin/pkg/auth/authorizer/rbac:go_default_library", "//plugin/pkg/auth/authorizer/rbac/bootstrappolicy:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authorization/authorizerfactory:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authorization/union:go_default_library", diff --git a/pkg/kubeapiserver/authorizer/config.go b/pkg/kubeapiserver/authorizer/config.go index a6542bfeaa0..cdbc11f48f3 100644 --- a/pkg/kubeapiserver/authorizer/config.go +++ b/pkg/kubeapiserver/authorizer/config.go @@ -20,6 +20,7 @@ import ( "fmt" "time" + utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizerfactory" "k8s.io/apiserver/pkg/authorization/union" @@ -54,6 +55,9 @@ type Config struct { WebhookCacheUnauthorizedTTL time.Duration VersionedInformerFactory versionedinformers.SharedInformerFactory + + // Optional field, custom dial function used to connect to webhook + CustomDial utilnet.DialFunc } // New returns the right sort of union of multiple authorizer.Authorizer objects @@ -102,7 +106,8 @@ func (config Config) New() (authorizer.Authorizer, authorizer.RuleResolver, erro webhookAuthorizer, err := webhook.New(config.WebhookConfigFile, config.WebhookVersion, config.WebhookCacheAuthorizedTTL, - config.WebhookCacheUnauthorizedTTL) + config.WebhookCacheUnauthorizedTTL, + config.CustomDial) if err != nil { return nil, nil, err } diff --git a/staging/src/k8s.io/apiserver/pkg/util/webhook/BUILD b/staging/src/k8s.io/apiserver/pkg/util/webhook/BUILD index 91717516b83..d8b20370007 100644 --- a/staging/src/k8s.io/apiserver/pkg/util/webhook/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/util/webhook/BUILD @@ -29,7 +29,6 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/server/egressselector:go_default_library", "//staging/src/k8s.io/client-go/rest:go_default_library", "//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library", "//staging/src/k8s.io/client-go/tools/clientcmd/api:go_default_library", diff --git a/staging/src/k8s.io/apiserver/pkg/util/webhook/webhook.go b/staging/src/k8s.io/apiserver/pkg/util/webhook/webhook.go index 8975129b0b1..1ac14fb00b6 100644 --- a/staging/src/k8s.io/apiserver/pkg/util/webhook/webhook.go +++ b/staging/src/k8s.io/apiserver/pkg/util/webhook/webhook.go @@ -29,7 +29,6 @@ import ( "k8s.io/apimachinery/pkg/util/net" utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/apiserver/pkg/server/egressselector" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" ) @@ -63,11 +62,11 @@ func DefaultShouldRetry(err error) bool { } // NewGenericWebhook creates a new GenericWebhook from the provided kubeconfig file. -func NewGenericWebhook(scheme *runtime.Scheme, codecFactory serializer.CodecFactory, kubeConfigFile string, groupVersions []schema.GroupVersion, initialBackoff time.Duration, egressLookup egressselector.Lookup) (*GenericWebhook, error) { - return newGenericWebhook(scheme, codecFactory, kubeConfigFile, groupVersions, initialBackoff, defaultRequestTimeout, egressLookup) +func NewGenericWebhook(scheme *runtime.Scheme, codecFactory serializer.CodecFactory, kubeConfigFile string, groupVersions []schema.GroupVersion, initialBackoff time.Duration, customDial utilnet.DialFunc) (*GenericWebhook, error) { + return newGenericWebhook(scheme, codecFactory, kubeConfigFile, groupVersions, initialBackoff, defaultRequestTimeout, customDial) } -func newGenericWebhook(scheme *runtime.Scheme, codecFactory serializer.CodecFactory, kubeConfigFile string, groupVersions []schema.GroupVersion, initialBackoff, requestTimeout time.Duration, egressLookup egressselector.Lookup) (*GenericWebhook, error) { +func newGenericWebhook(scheme *runtime.Scheme, codecFactory serializer.CodecFactory, kubeConfigFile string, groupVersions []schema.GroupVersion, initialBackoff, requestTimeout time.Duration, customDial utilnet.DialFunc) (*GenericWebhook, error) { for _, groupVersion := range groupVersions { if !scheme.IsVersionRegistered(groupVersion) { return nil, fmt.Errorf("webhook plugin requires enabling extension resource: %s", groupVersion) @@ -96,14 +95,9 @@ func newGenericWebhook(scheme *runtime.Scheme, codecFactory serializer.CodecFact codec := codecFactory.LegacyCodec(groupVersions...) clientConfig.ContentConfig.NegotiatedSerializer = serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: codec}) - if egressLookup != nil { - networkContext := egressselector.Master.AsNetworkContext() - var egressDialer utilnet.DialFunc - egressDialer, err = egressLookup(networkContext) - if err != nil { - return nil, err - } - clientConfig.Dial = egressDialer + + if customDial != nil { + clientConfig.Dial = customDial } restClient, err := rest.UnversionedRESTClientFor(clientConfig) diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/BUILD b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/BUILD index 9159bcb5f89..2de5ec78738 100644 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/BUILD +++ b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/BUILD @@ -39,9 +39,9 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/server/egressselector:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/webhook:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/typed/authentication/v1:go_default_library", diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/webhook.go b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/webhook.go index 1d5a90f6b8e..8307dd6f32d 100644 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/webhook.go +++ b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook/webhook.go @@ -28,9 +28,9 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/authentication/user" - "k8s.io/apiserver/pkg/server/egressselector" "k8s.io/apiserver/pkg/util/webhook" "k8s.io/client-go/kubernetes/scheme" authenticationv1client "k8s.io/client-go/kubernetes/typed/authentication/v1" @@ -64,8 +64,8 @@ func NewFromInterface(tokenReview authenticationv1client.TokenReviewInterface, i // file. It is recommend to wrap this authenticator with the token cache // authenticator implemented in // k8s.io/apiserver/pkg/authentication/token/cache. -func New(kubeConfigFile string, version string, implicitAuds authenticator.Audiences, egressLookup egressselector.Lookup) (*WebhookTokenAuthenticator, error) { - tokenReview, err := tokenReviewInterfaceFromKubeconfig(kubeConfigFile, version, egressLookup) +func New(kubeConfigFile string, version string, implicitAuds authenticator.Audiences, customDial utilnet.DialFunc) (*WebhookTokenAuthenticator, error) { + tokenReview, err := tokenReviewInterfaceFromKubeconfig(kubeConfigFile, version, customDial) if err != nil { return nil, err } @@ -154,7 +154,7 @@ func (w *WebhookTokenAuthenticator) AuthenticateToken(ctx context.Context, token // tokenReviewInterfaceFromKubeconfig builds a client from the specified kubeconfig file, // and returns a TokenReviewInterface that uses that client. Note that the client submits TokenReview // requests to the exact path specified in the kubeconfig file, so arbitrary non-API servers can be targeted. -func tokenReviewInterfaceFromKubeconfig(kubeConfigFile string, version string, egressLookup egressselector.Lookup) (tokenReviewer, error) { +func tokenReviewInterfaceFromKubeconfig(kubeConfigFile string, version string, customDial utilnet.DialFunc) (tokenReviewer, error) { localScheme := runtime.NewScheme() if err := scheme.AddToScheme(localScheme); err != nil { return nil, err @@ -166,7 +166,7 @@ func tokenReviewInterfaceFromKubeconfig(kubeConfigFile string, version string, e if err := localScheme.SetVersionPriority(groupVersions...); err != nil { return nil, err } - gw, err := webhook.NewGenericWebhook(localScheme, scheme.Codecs, kubeConfigFile, groupVersions, 0, egressLookup) + gw, err := webhook.NewGenericWebhook(localScheme, scheme.Codecs, kubeConfigFile, groupVersions, 0, customDial) if err != nil { return nil, err } @@ -177,7 +177,7 @@ func tokenReviewInterfaceFromKubeconfig(kubeConfigFile string, version string, e if err := localScheme.SetVersionPriority(groupVersions...); err != nil { return nil, err } - gw, err := webhook.NewGenericWebhook(localScheme, scheme.Codecs, kubeConfigFile, groupVersions, 0, egressLookup) + gw, err := webhook.NewGenericWebhook(localScheme, scheme.Codecs, kubeConfigFile, groupVersions, 0, customDial) if err != nil { return nil, err } diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/BUILD b/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/BUILD index b3208931c75..60276052359 100644 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/BUILD +++ b/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/BUILD @@ -39,6 +39,7 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/cache:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/webhook:go_default_library", diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook.go b/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook.go index b496b6c5874..3383700640d 100644 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook.go +++ b/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook.go @@ -31,6 +31,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/cache" + utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/util/webhook" @@ -84,8 +85,8 @@ func NewFromInterface(subjectAccessReview authorizationv1client.SubjectAccessRev // // For additional HTTP configuration, refer to the kubeconfig documentation // https://kubernetes.io/docs/user-guide/kubeconfig-file/. -func New(kubeConfigFile string, version string, authorizedTTL, unauthorizedTTL time.Duration) (*WebhookAuthorizer, error) { - subjectAccessReview, err := subjectAccessReviewInterfaceFromKubeconfig(kubeConfigFile, version) +func New(kubeConfigFile string, version string, authorizedTTL, unauthorizedTTL time.Duration, customDial utilnet.DialFunc) (*WebhookAuthorizer, error) { + subjectAccessReview, err := subjectAccessReviewInterfaceFromKubeconfig(kubeConfigFile, version, customDial) if err != nil { return nil, err } @@ -245,7 +246,7 @@ func convertToSARExtra(extra map[string][]string) map[string]authorizationv1.Ext // subjectAccessReviewInterfaceFromKubeconfig builds a client from the specified kubeconfig file, // and returns a SubjectAccessReviewInterface that uses that client. Note that the client submits SubjectAccessReview // requests to the exact path specified in the kubeconfig file, so arbitrary non-API servers can be targeted. -func subjectAccessReviewInterfaceFromKubeconfig(kubeConfigFile string, version string) (subjectAccessReviewer, error) { +func subjectAccessReviewInterfaceFromKubeconfig(kubeConfigFile string, version string, customDial utilnet.DialFunc) (subjectAccessReviewer, error) { localScheme := runtime.NewScheme() if err := scheme.AddToScheme(localScheme); err != nil { return nil, err @@ -257,7 +258,7 @@ func subjectAccessReviewInterfaceFromKubeconfig(kubeConfigFile string, version s if err := localScheme.SetVersionPriority(groupVersions...); err != nil { return nil, err } - gw, err := webhook.NewGenericWebhook(localScheme, scheme.Codecs, kubeConfigFile, groupVersions, 0, nil) + gw, err := webhook.NewGenericWebhook(localScheme, scheme.Codecs, kubeConfigFile, groupVersions, 0, customDial) if err != nil { return nil, err } @@ -268,7 +269,7 @@ func subjectAccessReviewInterfaceFromKubeconfig(kubeConfigFile string, version s if err := localScheme.SetVersionPriority(groupVersions...); err != nil { return nil, err } - gw, err := webhook.NewGenericWebhook(localScheme, scheme.Codecs, kubeConfigFile, groupVersions, 0, nil) + gw, err := webhook.NewGenericWebhook(localScheme, scheme.Codecs, kubeConfigFile, groupVersions, 0, customDial) if err != nil { return nil, err } diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1_test.go b/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1_test.go index 4fb870d24a6..f1ccc84d7b2 100644 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1_test.go +++ b/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1_test.go @@ -186,7 +186,7 @@ current-context: default return fmt.Errorf("failed to execute test template: %v", err) } // Create a new authorizer - sarClient, err := subjectAccessReviewInterfaceFromKubeconfig(p, "v1") + sarClient, err := subjectAccessReviewInterfaceFromKubeconfig(p, "v1", nil) if err != nil { return fmt.Errorf("error building sar client: %v", err) } @@ -325,7 +325,7 @@ func newV1Authorizer(callbackURL string, clientCert, clientKey, ca []byte, cache if err := json.NewEncoder(tempfile).Encode(config); err != nil { return nil, err } - sarClient, err := subjectAccessReviewInterfaceFromKubeconfig(p, "v1") + sarClient, err := subjectAccessReviewInterfaceFromKubeconfig(p, "v1", nil) if err != nil { return nil, fmt.Errorf("error building sar client: %v", err) } diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1beta1_test.go b/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1beta1_test.go index 53841f743a5..7d664883d75 100644 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1beta1_test.go +++ b/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1beta1_test.go @@ -186,7 +186,7 @@ current-context: default return fmt.Errorf("failed to execute test template: %v", err) } // Create a new authorizer - sarClient, err := subjectAccessReviewInterfaceFromKubeconfig(p, "v1beta1") + sarClient, err := subjectAccessReviewInterfaceFromKubeconfig(p, "v1beta1", nil) if err != nil { return fmt.Errorf("error building sar client: %v", err) } @@ -325,7 +325,7 @@ func newV1beta1Authorizer(callbackURL string, clientCert, clientKey, ca []byte, if err := json.NewEncoder(tempfile).Encode(config); err != nil { return nil, err } - sarClient, err := subjectAccessReviewInterfaceFromKubeconfig(p, "v1beta1") + sarClient, err := subjectAccessReviewInterfaceFromKubeconfig(p, "v1beta1", nil) if err != nil { return nil, fmt.Errorf("error building sar client: %v", err) } diff --git a/test/integration/auth/BUILD b/test/integration/auth/BUILD index 70a0c7010f3..b741619dcca 100644 --- a/test/integration/auth/BUILD +++ b/test/integration/auth/BUILD @@ -59,6 +59,7 @@ go_test( "//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library", diff --git a/test/integration/auth/auth_test.go b/test/integration/auth/auth_test.go index 49418001e29..421eef801c6 100644 --- a/test/integration/auth/auth_test.go +++ b/test/integration/auth/auth_test.go @@ -37,6 +37,7 @@ import ( authenticationv1beta1 "k8s.io/api/authentication/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/authentication/group" "k8s.io/apiserver/pkg/authentication/request/bearertoken" @@ -69,7 +70,7 @@ func getTestTokenAuth() authenticator.Request { return group.NewGroupAdder(bearertoken.New(tokenAuthenticator), []string{user.AllAuthenticated}) } -func getTestWebhookTokenAuth(serverURL string) (authenticator.Request, error) { +func getTestWebhookTokenAuth(serverURL string, customDial utilnet.DialFunc) (authenticator.Request, error) { kubecfgFile, err := ioutil.TempFile("", "webhook-kubecfg") if err != nil { return nil, err @@ -85,13 +86,19 @@ func getTestWebhookTokenAuth(serverURL string) (authenticator.Request, error) { if err := json.NewEncoder(kubecfgFile).Encode(config); err != nil { return nil, err } - webhookTokenAuth, err := webhook.New(kubecfgFile.Name(), "v1beta1", nil, nil) + webhookTokenAuth, err := webhook.New(kubecfgFile.Name(), "v1beta1", nil, customDial) if err != nil { return nil, err } return bearertoken.New(cache.New(webhookTokenAuth, false, 2*time.Minute, 2*time.Minute)), nil } +func getTestWebhookTokenAuthCustomDialer(serverURL string) (authenticator.Request, error) { + customDial := http.DefaultTransport.(*http.Transport).DialContext + + return getTestWebhookTokenAuth(serverURL, customDial) +} + func path(resource, namespace, name string) string { return pathWithPrefix("", resource, namespace, name) } @@ -1192,9 +1199,27 @@ func TestReadOnlyAuthorization(t *testing.T) { // authenticator to call out to a remote web server for authentication // decisions. func TestWebhookTokenAuthenticator(t *testing.T) { + testWebhookTokenAuthenticator(false, t) +} + +// TestWebhookTokenAuthenticatorCustomDial is the same as TestWebhookTokenAuthenticator, but uses a +// custom dialer +func TestWebhookTokenAuthenticatorCustomDial(t *testing.T) { + testWebhookTokenAuthenticator(true, t) +} + +func testWebhookTokenAuthenticator(customDialer bool, t *testing.T) { authServer := newTestWebhookTokenAuthServer() defer authServer.Close() - authenticator, err := getTestWebhookTokenAuth(authServer.URL) + var authenticator authenticator.Request + var err error + + if customDialer == false { + authenticator, err = getTestWebhookTokenAuth(authServer.URL, nil) + } else { + authenticator, err = getTestWebhookTokenAuthCustomDialer(authServer.URL) + } + if err != nil { t.Fatalf("error starting webhook token authenticator server: %v", err) } From cd57b830c142e2b9938ff801619070cf601c1422 Mon Sep 17 00:00:00 2001 From: Jefftree Date: Thu, 19 Dec 2019 12:29:37 -0800 Subject: [PATCH 3/4] audit webhook use network proxy --- .../apiserver/pkg/server/options/audit.go | 17 ++++++++++++++--- .../apiserver/plugin/pkg/audit/webhook/BUILD | 1 + .../plugin/pkg/audit/webhook/webhook.go | 9 +++++---- .../plugin/pkg/audit/webhook/webhook_test.go | 2 +- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/audit.go b/staging/src/k8s.io/apiserver/pkg/server/options/audit.go index 98b3fc615c2..090ef5a2b50 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/audit.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/audit.go @@ -29,6 +29,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime/schema" + utilnet "k8s.io/apimachinery/pkg/util/net" auditinternal "k8s.io/apiserver/pkg/apis/audit" auditv1 "k8s.io/apiserver/pkg/apis/audit/v1" auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1" @@ -37,6 +38,7 @@ import ( "k8s.io/apiserver/pkg/audit/policy" "k8s.io/apiserver/pkg/features" "k8s.io/apiserver/pkg/server" + "k8s.io/apiserver/pkg/server/egressselector" utilfeature "k8s.io/apiserver/pkg/util/feature" pluginbuffered "k8s.io/apiserver/plugin/pkg/audit/buffered" plugindynamic "k8s.io/apiserver/plugin/pkg/audit/dynamic" @@ -323,7 +325,16 @@ func (o *AuditOptions) ApplyTo( if checker == nil { klog.V(2).Info("No audit policy file provided, no events will be recorded for webhook backend") } else { - webhookBackend, err = o.WebhookOptions.newUntruncatedBackend() + + if c.EgressSelector != nil { + egressDialer, err := c.EgressSelector.Lookup(egressselector.Master.AsNetworkContext()) + if err != nil { + return err + } + webhookBackend, err = o.WebhookOptions.newUntruncatedBackend(egressDialer) + } else { + webhookBackend, err = o.WebhookOptions.newUntruncatedBackend(nil) + } if err != nil { return err } @@ -590,9 +601,9 @@ func (o *AuditWebhookOptions) enabled() bool { // newUntruncatedBackend returns a webhook backend without the truncate options applied // this is done so that the same trucate backend can wrap both the webhook and dynamic backends -func (o *AuditWebhookOptions) newUntruncatedBackend() (audit.Backend, error) { +func (o *AuditWebhookOptions) newUntruncatedBackend(customDial utilnet.DialFunc) (audit.Backend, error) { groupVersion, _ := schema.ParseGroupVersion(o.GroupVersionString) - webhook, err := pluginwebhook.NewBackend(o.ConfigFile, groupVersion, o.InitialBackoff) + webhook, err := pluginwebhook.NewBackend(o.ConfigFile, groupVersion, o.InitialBackoff, customDial) if err != nil { return nil, fmt.Errorf("initializing audit webhook: %v", err) } diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/audit/webhook/BUILD b/staging/src/k8s.io/apiserver/plugin/pkg/audit/webhook/BUILD index 67c2f76a9f5..f73bd537467 100644 --- a/staging/src/k8s.io/apiserver/plugin/pkg/audit/webhook/BUILD +++ b/staging/src/k8s.io/apiserver/plugin/pkg/audit/webhook/BUILD @@ -31,6 +31,7 @@ go_library( importpath = "k8s.io/apiserver/plugin/pkg/audit/webhook", deps = [ "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library", "//staging/src/k8s.io/apiserver/pkg/apis/audit:go_default_library", "//staging/src/k8s.io/apiserver/pkg/apis/audit/install:go_default_library", "//staging/src/k8s.io/apiserver/pkg/audit:go_default_library", diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/audit/webhook/webhook.go b/staging/src/k8s.io/apiserver/plugin/pkg/audit/webhook/webhook.go index 861ec72dd3e..09933733102 100644 --- a/staging/src/k8s.io/apiserver/plugin/pkg/audit/webhook/webhook.go +++ b/staging/src/k8s.io/apiserver/plugin/pkg/audit/webhook/webhook.go @@ -23,6 +23,7 @@ import ( "time" "k8s.io/apimachinery/pkg/runtime/schema" + utilnet "k8s.io/apimachinery/pkg/util/net" auditinternal "k8s.io/apiserver/pkg/apis/audit" "k8s.io/apiserver/pkg/apis/audit/install" "k8s.io/apiserver/pkg/audit" @@ -60,9 +61,9 @@ func retryOnError(err error) bool { return false } -func loadWebhook(configFile string, groupVersion schema.GroupVersion, initialBackoff time.Duration) (*webhook.GenericWebhook, error) { +func loadWebhook(configFile string, groupVersion schema.GroupVersion, initialBackoff time.Duration, customDial utilnet.DialFunc) (*webhook.GenericWebhook, error) { w, err := webhook.NewGenericWebhook(audit.Scheme, audit.Codecs, configFile, - []schema.GroupVersion{groupVersion}, initialBackoff, nil) + []schema.GroupVersion{groupVersion}, initialBackoff, customDial) w.ShouldRetry = retryOnError return w, err } @@ -86,8 +87,8 @@ func NewDynamicBackend(rc *rest.RESTClient, initialBackoff time.Duration) audit. } // NewBackend returns an audit backend that sends events over HTTP to an external service. -func NewBackend(kubeConfigFile string, groupVersion schema.GroupVersion, initialBackoff time.Duration) (audit.Backend, error) { - w, err := loadWebhook(kubeConfigFile, groupVersion, initialBackoff) +func NewBackend(kubeConfigFile string, groupVersion schema.GroupVersion, initialBackoff time.Duration, customDial utilnet.DialFunc) (audit.Backend, error) { + w, err := loadWebhook(kubeConfigFile, groupVersion, initialBackoff, customDial) if err != nil { return nil, err } diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/audit/webhook/webhook_test.go b/staging/src/k8s.io/apiserver/plugin/pkg/audit/webhook/webhook_test.go index 7d5dfd0c842..9c23589945c 100644 --- a/staging/src/k8s.io/apiserver/plugin/pkg/audit/webhook/webhook_test.go +++ b/staging/src/k8s.io/apiserver/plugin/pkg/audit/webhook/webhook_test.go @@ -106,7 +106,7 @@ func newWebhook(t *testing.T, endpoint string, groupVersion schema.GroupVersion) // NOTE(ericchiang): Do we need to use a proper serializer? require.NoError(t, stdjson.NewEncoder(f).Encode(config), "writing kubeconfig") - b, err := NewBackend(f.Name(), groupVersion, DefaultInitialBackoff) + b, err := NewBackend(f.Name(), groupVersion, DefaultInitialBackoff, nil) require.NoError(t, err, "initializing backend") return b.(*backend) From 61fa4e6c098559b65fe28c1bf55cb817697e38e5 Mon Sep 17 00:00:00 2001 From: Jefftree Date: Thu, 27 Feb 2020 17:18:57 -0800 Subject: [PATCH 4/4] Address comment and remove if condition --- staging/src/k8s.io/apiserver/pkg/server/options/audit.go | 1 - staging/src/k8s.io/apiserver/pkg/util/webhook/BUILD | 1 + staging/src/k8s.io/apiserver/pkg/util/webhook/webhook.go | 4 +--- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/audit.go b/staging/src/k8s.io/apiserver/pkg/server/options/audit.go index 090ef5a2b50..8a3503cab36 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/audit.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/audit.go @@ -325,7 +325,6 @@ func (o *AuditOptions) ApplyTo( if checker == nil { klog.V(2).Info("No audit policy file provided, no events will be recorded for webhook backend") } else { - if c.EgressSelector != nil { egressDialer, err := c.EgressSelector.Lookup(egressselector.Master.AsNetworkContext()) if err != nil { diff --git a/staging/src/k8s.io/apiserver/pkg/util/webhook/BUILD b/staging/src/k8s.io/apiserver/pkg/util/webhook/BUILD index d8b20370007..91717516b83 100644 --- a/staging/src/k8s.io/apiserver/pkg/util/webhook/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/util/webhook/BUILD @@ -29,6 +29,7 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/server/egressselector:go_default_library", "//staging/src/k8s.io/client-go/rest:go_default_library", "//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library", "//staging/src/k8s.io/client-go/tools/clientcmd/api:go_default_library", diff --git a/staging/src/k8s.io/apiserver/pkg/util/webhook/webhook.go b/staging/src/k8s.io/apiserver/pkg/util/webhook/webhook.go index 1ac14fb00b6..f067466afaa 100644 --- a/staging/src/k8s.io/apiserver/pkg/util/webhook/webhook.go +++ b/staging/src/k8s.io/apiserver/pkg/util/webhook/webhook.go @@ -96,9 +96,7 @@ func newGenericWebhook(scheme *runtime.Scheme, codecFactory serializer.CodecFact codec := codecFactory.LegacyCodec(groupVersions...) clientConfig.ContentConfig.NegotiatedSerializer = serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: codec}) - if customDial != nil { - clientConfig.Dial = customDial - } + clientConfig.Dial = customDial restClient, err := rest.UnversionedRESTClientFor(clientConfig) if err != nil {