diff --git a/pkg/util/webhook/webhook.go b/pkg/util/webhook/webhook.go index d2c6e2273..8975129b0 100644 --- a/pkg/util/webhook/webhook.go +++ b/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/pkg/util/webhook/webhook_test.go b/pkg/util/webhook/webhook_test.go index 7fda70874..b70d146e8 100644 --- a/pkg/util/webhook/webhook_test.go +++ b/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/plugin/pkg/audit/webhook/webhook.go b/plugin/pkg/audit/webhook/webhook.go index f73c1fd56..861ec72dd 100644 --- a/plugin/pkg/audit/webhook/webhook.go +++ b/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/plugin/pkg/authenticator/token/webhook/webhook.go b/plugin/pkg/authenticator/token/webhook/webhook.go index 7410d1959..1d5a90f6b 100644 --- a/plugin/pkg/authenticator/token/webhook/webhook.go +++ b/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/plugin/pkg/authenticator/token/webhook/webhook_v1_test.go b/plugin/pkg/authenticator/token/webhook/webhook_v1_test.go index 884317242..e9bf2a36d 100644 --- a/plugin/pkg/authenticator/token/webhook/webhook_v1_test.go +++ b/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/plugin/pkg/authenticator/token/webhook/webhook_v1beta1_test.go b/plugin/pkg/authenticator/token/webhook/webhook_v1beta1_test.go index 514fd9df3..e5ea01bae 100644 --- a/plugin/pkg/authenticator/token/webhook/webhook_v1beta1_test.go +++ b/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/plugin/pkg/authorizer/webhook/webhook.go b/plugin/pkg/authorizer/webhook/webhook.go index cc8b5e78b..b496b6c58 100644 --- a/plugin/pkg/authorizer/webhook/webhook.go +++ b/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 }