Skip to content

Commit 268d0a1

Browse files
authored
Merge pull request kubernetes#85870 from Jefftree/authn-netproxy
Use Network Proxy with Authentication & Authorizer Webhooks
2 parents a54e1a8 + 61fa4e6 commit 268d0a1

File tree

22 files changed

+119
-45
lines changed

22 files changed

+119
-45
lines changed

cmd/kube-apiserver/app/server.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -498,13 +498,13 @@ func buildGenericConfig(
498498
}
499499
versionedInformers = clientgoinformers.NewSharedInformerFactory(clientgoExternalClient, 10*time.Minute)
500500

501-
genericConfig.Authentication.Authenticator, genericConfig.OpenAPIConfig.SecurityDefinitions, err = BuildAuthenticator(s, clientgoExternalClient, versionedInformers)
501+
genericConfig.Authentication.Authenticator, genericConfig.OpenAPIConfig.SecurityDefinitions, err = BuildAuthenticator(s, genericConfig.EgressSelector, clientgoExternalClient, versionedInformers)
502502
if err != nil {
503503
lastErr = fmt.Errorf("invalid authentication config: %v", err)
504504
return
505505
}
506506

507-
genericConfig.Authorization.Authorizer, genericConfig.RuleResolver, err = BuildAuthorizer(s, versionedInformers)
507+
genericConfig.Authorization.Authorizer, genericConfig.RuleResolver, err = BuildAuthorizer(s, genericConfig.EgressSelector, versionedInformers)
508508
if err != nil {
509509
lastErr = fmt.Errorf("invalid authorization config: %v", err)
510510
return
@@ -560,7 +560,7 @@ func buildGenericConfig(
560560
}
561561

562562
// BuildAuthenticator constructs the authenticator
563-
func BuildAuthenticator(s *options.ServerRunOptions, extclient clientgoclientset.Interface, versionedInformer clientgoinformers.SharedInformerFactory) (authenticator.Request, *spec.SecurityDefinitions, error) {
563+
func BuildAuthenticator(s *options.ServerRunOptions, EgressSelector *egressselector.EgressSelector, extclient clientgoclientset.Interface, versionedInformer clientgoinformers.SharedInformerFactory) (authenticator.Request, *spec.SecurityDefinitions, error) {
564564
authenticatorConfig, err := s.Authentication.ToAuthenticationConfig()
565565
if err != nil {
566566
return nil, nil, err
@@ -577,12 +577,29 @@ func BuildAuthenticator(s *options.ServerRunOptions, extclient clientgoclientset
577577
versionedInformer.Core().V1().Secrets().Lister().Secrets(v1.NamespaceSystem),
578578
)
579579

580+
if EgressSelector != nil {
581+
egressDialer, err := EgressSelector.Lookup(egressselector.Master.AsNetworkContext())
582+
if err != nil {
583+
return nil, nil, err
584+
}
585+
authenticatorConfig.CustomDial = egressDialer
586+
}
587+
580588
return authenticatorConfig.New()
581589
}
582590

583591
// BuildAuthorizer constructs the authorizer
584-
func BuildAuthorizer(s *options.ServerRunOptions, versionedInformers clientgoinformers.SharedInformerFactory) (authorizer.Authorizer, authorizer.RuleResolver, error) {
592+
func BuildAuthorizer(s *options.ServerRunOptions, EgressSelector *egressselector.EgressSelector, versionedInformers clientgoinformers.SharedInformerFactory) (authorizer.Authorizer, authorizer.RuleResolver, error) {
585593
authorizationConfig := s.Authorization.ToAuthorizationConfig(versionedInformers)
594+
595+
if EgressSelector != nil {
596+
egressDialer, err := EgressSelector.Lookup(egressselector.Master.AsNetworkContext())
597+
if err != nil {
598+
return nil, nil, err
599+
}
600+
authorizationConfig.CustomDial = egressDialer
601+
}
602+
586603
return authorizationConfig.New()
587604
}
588605

pkg/kubeapiserver/authenticator/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ go_library(
1212
deps = [
1313
"//pkg/features:go_default_library",
1414
"//pkg/serviceaccount:go_default_library",
15+
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
1516
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
1617
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticatorfactory:go_default_library",
1718
"//staging/src/k8s.io/apiserver/pkg/authentication/group:go_default_library",

pkg/kubeapiserver/authenticator/config.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
"github.com/go-openapi/spec"
2323

24+
utilnet "k8s.io/apimachinery/pkg/util/net"
2425
"k8s.io/apiserver/pkg/authentication/authenticator"
2526
"k8s.io/apiserver/pkg/authentication/authenticatorfactory"
2627
"k8s.io/apiserver/pkg/authentication/group"
@@ -83,6 +84,9 @@ type Config struct {
8384
// Generally this is the CA bundle file used to authenticate client certificates
8485
// If this value is nil, then mutual TLS is disabled.
8586
ClientCAContentProvider dynamiccertificates.CAContentProvider
87+
88+
// Optional field, custom dial function used to connect to webhook
89+
CustomDial utilnet.DialFunc
8690
}
8791

8892
// 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
179183
tokenAuthenticators = append(tokenAuthenticators, authenticator.WrapAudienceAgnosticToken(config.APIAudiences, oidcAuth))
180184
}
181185
if len(config.WebhookTokenAuthnConfigFile) > 0 {
182-
webhookTokenAuth, err := newWebhookTokenAuthenticator(config.WebhookTokenAuthnConfigFile, config.WebhookTokenAuthnVersion, config.WebhookTokenAuthnCacheTTL, config.APIAudiences)
186+
webhookTokenAuth, err := newWebhookTokenAuthenticator(config)
183187
if err != nil {
184188
return nil, nil, err
185189
}
190+
186191
tokenAuthenticators = append(tokenAuthenticators, webhookTokenAuth)
187192
}
188193

@@ -305,11 +310,11 @@ func newServiceAccountAuthenticator(iss string, keyfiles []string, apiAudiences
305310
return tokenAuthenticator, nil
306311
}
307312

308-
func newWebhookTokenAuthenticator(webhookConfigFile string, version string, ttl time.Duration, implicitAuds authenticator.Audiences) (authenticator.Token, error) {
309-
webhookTokenAuthenticator, err := webhook.New(webhookConfigFile, version, implicitAuds)
313+
func newWebhookTokenAuthenticator(config Config) (authenticator.Token, error) {
314+
webhookTokenAuthenticator, err := webhook.New(config.WebhookTokenAuthnConfigFile, config.WebhookTokenAuthnVersion, config.APIAudiences, config.CustomDial)
310315
if err != nil {
311316
return nil, err
312317
}
313318

314-
return tokencache.New(webhookTokenAuthenticator, false, ttl, ttl), nil
319+
return tokencache.New(webhookTokenAuthenticator, false, config.WebhookTokenAuthnCacheTTL, config.WebhookTokenAuthnCacheTTL), nil
315320
}

pkg/kubeapiserver/authorizer/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ go_library(
1616
"//plugin/pkg/auth/authorizer/node:go_default_library",
1717
"//plugin/pkg/auth/authorizer/rbac:go_default_library",
1818
"//plugin/pkg/auth/authorizer/rbac/bootstrappolicy:go_default_library",
19+
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
1920
"//staging/src/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
2021
"//staging/src/k8s.io/apiserver/pkg/authorization/authorizerfactory:go_default_library",
2122
"//staging/src/k8s.io/apiserver/pkg/authorization/union:go_default_library",

pkg/kubeapiserver/authorizer/config.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"fmt"
2121
"time"
2222

23+
utilnet "k8s.io/apimachinery/pkg/util/net"
2324
"k8s.io/apiserver/pkg/authorization/authorizer"
2425
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
2526
"k8s.io/apiserver/pkg/authorization/union"
@@ -54,6 +55,9 @@ type Config struct {
5455
WebhookCacheUnauthorizedTTL time.Duration
5556

5657
VersionedInformerFactory versionedinformers.SharedInformerFactory
58+
59+
// Optional field, custom dial function used to connect to webhook
60+
CustomDial utilnet.DialFunc
5761
}
5862

5963
// 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
102106
webhookAuthorizer, err := webhook.New(config.WebhookConfigFile,
103107
config.WebhookVersion,
104108
config.WebhookCacheAuthorizedTTL,
105-
config.WebhookCacheUnauthorizedTTL)
109+
config.WebhookCacheUnauthorizedTTL,
110+
config.CustomDial)
106111
if err != nil {
107112
return nil, nil, err
108113
}

plugin/pkg/admission/imagepolicy/admission.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ func NewImagePolicyWebhook(configFile io.Reader) (*Plugin, error) {
261261
return nil, err
262262
}
263263

264-
gw, err := webhook.NewGenericWebhook(legacyscheme.Scheme, legacyscheme.Codecs, whConfig.KubeConfigFile, groupVersions, whConfig.RetryBackoff)
264+
gw, err := webhook.NewGenericWebhook(legacyscheme.Scheme, legacyscheme.Codecs, whConfig.KubeConfigFile, groupVersions, whConfig.RetryBackoff, nil)
265265
if err != nil {
266266
return nil, err
267267
}

staging/src/k8s.io/apiserver/pkg/server/options/audit.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929

3030
corev1 "k8s.io/api/core/v1"
3131
"k8s.io/apimachinery/pkg/runtime/schema"
32+
utilnet "k8s.io/apimachinery/pkg/util/net"
3233
auditinternal "k8s.io/apiserver/pkg/apis/audit"
3334
auditv1 "k8s.io/apiserver/pkg/apis/audit/v1"
3435
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
@@ -37,6 +38,7 @@ import (
3738
"k8s.io/apiserver/pkg/audit/policy"
3839
"k8s.io/apiserver/pkg/features"
3940
"k8s.io/apiserver/pkg/server"
41+
"k8s.io/apiserver/pkg/server/egressselector"
4042
utilfeature "k8s.io/apiserver/pkg/util/feature"
4143
pluginbuffered "k8s.io/apiserver/plugin/pkg/audit/buffered"
4244
plugindynamic "k8s.io/apiserver/plugin/pkg/audit/dynamic"
@@ -323,7 +325,15 @@ func (o *AuditOptions) ApplyTo(
323325
if checker == nil {
324326
klog.V(2).Info("No audit policy file provided, no events will be recorded for webhook backend")
325327
} else {
326-
webhookBackend, err = o.WebhookOptions.newUntruncatedBackend()
328+
if c.EgressSelector != nil {
329+
egressDialer, err := c.EgressSelector.Lookup(egressselector.Master.AsNetworkContext())
330+
if err != nil {
331+
return err
332+
}
333+
webhookBackend, err = o.WebhookOptions.newUntruncatedBackend(egressDialer)
334+
} else {
335+
webhookBackend, err = o.WebhookOptions.newUntruncatedBackend(nil)
336+
}
327337
if err != nil {
328338
return err
329339
}
@@ -590,9 +600,9 @@ func (o *AuditWebhookOptions) enabled() bool {
590600

591601
// newUntruncatedBackend returns a webhook backend without the truncate options applied
592602
// this is done so that the same trucate backend can wrap both the webhook and dynamic backends
593-
func (o *AuditWebhookOptions) newUntruncatedBackend() (audit.Backend, error) {
603+
func (o *AuditWebhookOptions) newUntruncatedBackend(customDial utilnet.DialFunc) (audit.Backend, error) {
594604
groupVersion, _ := schema.ParseGroupVersion(o.GroupVersionString)
595-
webhook, err := pluginwebhook.NewBackend(o.ConfigFile, groupVersion, o.InitialBackoff)
605+
webhook, err := pluginwebhook.NewBackend(o.ConfigFile, groupVersion, o.InitialBackoff, customDial)
596606
if err != nil {
597607
return nil, fmt.Errorf("initializing audit webhook: %v", err)
598608
}

staging/src/k8s.io/apiserver/pkg/util/webhook/webhook.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"k8s.io/apimachinery/pkg/runtime/schema"
2828
"k8s.io/apimachinery/pkg/runtime/serializer"
2929
"k8s.io/apimachinery/pkg/util/net"
30+
utilnet "k8s.io/apimachinery/pkg/util/net"
3031
"k8s.io/apimachinery/pkg/util/wait"
3132
"k8s.io/client-go/rest"
3233
"k8s.io/client-go/tools/clientcmd"
@@ -61,11 +62,11 @@ func DefaultShouldRetry(err error) bool {
6162
}
6263

6364
// NewGenericWebhook creates a new GenericWebhook from the provided kubeconfig file.
64-
func NewGenericWebhook(scheme *runtime.Scheme, codecFactory serializer.CodecFactory, kubeConfigFile string, groupVersions []schema.GroupVersion, initialBackoff time.Duration) (*GenericWebhook, error) {
65-
return newGenericWebhook(scheme, codecFactory, kubeConfigFile, groupVersions, initialBackoff, defaultRequestTimeout)
65+
func NewGenericWebhook(scheme *runtime.Scheme, codecFactory serializer.CodecFactory, kubeConfigFile string, groupVersions []schema.GroupVersion, initialBackoff time.Duration, customDial utilnet.DialFunc) (*GenericWebhook, error) {
66+
return newGenericWebhook(scheme, codecFactory, kubeConfigFile, groupVersions, initialBackoff, defaultRequestTimeout, customDial)
6667
}
6768

68-
func newGenericWebhook(scheme *runtime.Scheme, codecFactory serializer.CodecFactory, kubeConfigFile string, groupVersions []schema.GroupVersion, initialBackoff, requestTimeout time.Duration) (*GenericWebhook, error) {
69+
func newGenericWebhook(scheme *runtime.Scheme, codecFactory serializer.CodecFactory, kubeConfigFile string, groupVersions []schema.GroupVersion, initialBackoff, requestTimeout time.Duration, customDial utilnet.DialFunc) (*GenericWebhook, error) {
6970
for _, groupVersion := range groupVersions {
7071
if !scheme.IsVersionRegistered(groupVersion) {
7172
return nil, fmt.Errorf("webhook plugin requires enabling extension resource: %s", groupVersion)
@@ -95,6 +96,8 @@ func newGenericWebhook(scheme *runtime.Scheme, codecFactory serializer.CodecFact
9596
codec := codecFactory.LegacyCodec(groupVersions...)
9697
clientConfig.ContentConfig.NegotiatedSerializer = serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: codec})
9798

99+
clientConfig.Dial = customDial
100+
98101
restClient, err := rest.UnversionedRESTClientFor(clientConfig)
99102
if err != nil {
100103
return nil, err

staging/src/k8s.io/apiserver/pkg/util/webhook/webhook_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ func TestKubeConfigFile(t *testing.T) {
259259
if err == nil {
260260
defer os.Remove(kubeConfigFile)
261261

262-
_, err = NewGenericWebhook(runtime.NewScheme(), scheme.Codecs, kubeConfigFile, groupVersions, retryBackoff)
262+
_, err = NewGenericWebhook(runtime.NewScheme(), scheme.Codecs, kubeConfigFile, groupVersions, retryBackoff, nil)
263263
}
264264

265265
return err
@@ -282,7 +282,7 @@ func TestKubeConfigFile(t *testing.T) {
282282
// TestMissingKubeConfigFile ensures that a kube config path to a missing file is handled properly
283283
func TestMissingKubeConfigFile(t *testing.T) {
284284
kubeConfigPath := "/some/missing/path"
285-
_, err := NewGenericWebhook(runtime.NewScheme(), scheme.Codecs, kubeConfigPath, groupVersions, retryBackoff)
285+
_, err := NewGenericWebhook(runtime.NewScheme(), scheme.Codecs, kubeConfigPath, groupVersions, retryBackoff, nil)
286286

287287
if err == nil {
288288
t.Errorf("creating the webhook should had failed")
@@ -394,7 +394,7 @@ func TestTLSConfig(t *testing.T) {
394394

395395
defer os.Remove(configFile)
396396

397-
wh, err := NewGenericWebhook(runtime.NewScheme(), scheme.Codecs, configFile, groupVersions, retryBackoff)
397+
wh, err := NewGenericWebhook(runtime.NewScheme(), scheme.Codecs, configFile, groupVersions, retryBackoff, nil)
398398

399399
if err == nil {
400400
err = wh.RestClient.Get().Do(context.TODO()).Error()
@@ -459,7 +459,7 @@ func TestRequestTimeout(t *testing.T) {
459459

460460
var requestTimeout = 10 * time.Millisecond
461461

462-
wh, err := newGenericWebhook(runtime.NewScheme(), scheme.Codecs, configFile, groupVersions, retryBackoff, requestTimeout)
462+
wh, err := newGenericWebhook(runtime.NewScheme(), scheme.Codecs, configFile, groupVersions, retryBackoff, requestTimeout, nil)
463463
if err != nil {
464464
t.Fatalf("failed to create the webhook: %v", err)
465465
}
@@ -545,7 +545,7 @@ func TestWithExponentialBackoff(t *testing.T) {
545545

546546
defer os.Remove(configFile)
547547

548-
wh, err := NewGenericWebhook(runtime.NewScheme(), scheme.Codecs, configFile, groupVersions, retryBackoff)
548+
wh, err := NewGenericWebhook(runtime.NewScheme(), scheme.Codecs, configFile, groupVersions, retryBackoff, nil)
549549

550550
if err != nil {
551551
t.Fatalf("failed to create the webhook: %v", err)

staging/src/k8s.io/apiserver/plugin/pkg/audit/webhook/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ go_library(
3131
importpath = "k8s.io/apiserver/plugin/pkg/audit/webhook",
3232
deps = [
3333
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
34+
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
3435
"//staging/src/k8s.io/apiserver/pkg/apis/audit:go_default_library",
3536
"//staging/src/k8s.io/apiserver/pkg/apis/audit/install:go_default_library",
3637
"//staging/src/k8s.io/apiserver/pkg/audit:go_default_library",

0 commit comments

Comments
 (0)