diff --git a/cmd/broker/filter/main.go b/cmd/broker/filter/main.go index 8d7d9612745..f30b250f4b8 100644 --- a/cmd/broker/filter/main.go +++ b/cmd/broker/filter/main.go @@ -131,7 +131,7 @@ func main() { } handler.EventTypeCreator = autoCreate } - + handler.TokenVerifier = auth.NewOIDCTokenVerifier(ctx, featureFlags) }) featureStore.WatchConfigs(configMapWatcher) @@ -151,7 +151,7 @@ func main() { oidcTokenProvider := auth.NewOIDCTokenProvider(ctx) // We are running both the receiver (takes messages in from the Broker) and the dispatcher (send // the messages to the triggers' subscribers) in this binary. - oidcTokenVerifier := auth.NewOIDCTokenVerifier(ctx) + oidcTokenVerifier := auth.NewOIDCTokenVerifier(ctx, featureStore.Load()) trustBundleConfigMapInformer := configmapinformer.Get(ctx, eventingtls.TrustBundleLabelSelector).Lister().ConfigMaps(system.Namespace()) handler, err = filter.NewHandler(logger, oidcTokenVerifier, oidcTokenProvider, triggerinformer.Get(ctx), brokerinformer.Get(ctx), reporter, trustBundleConfigMapInformer, ctxFunc) if err != nil { diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index 456154e7508..aa22fcd5d5a 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -156,6 +156,7 @@ func main() { } handler.EvenTypeHandler = autoCreate } + handler.TokenVerifier = auth.NewOIDCTokenVerifier(ctx, featureFlags) }) featureStore.WatchConfigs(configMapWatcher) @@ -167,7 +168,7 @@ func main() { reporter := ingress.NewStatsReporter(env.ContainerName, kmeta.ChildName(env.PodName, uuid.New().String())) oidcTokenProvider := auth.NewOIDCTokenProvider(ctx) - oidcTokenVerifier := auth.NewOIDCTokenVerifier(ctx) + oidcTokenVerifier := auth.NewOIDCTokenVerifier(ctx, featureStore.Load()) trustBundleConfigMapInformer := configmapinformer.Get(ctx, eventingtls.TrustBundleLabelSelector).Lister().ConfigMaps(system.Namespace()) handler, err = ingress.NewHandler(logger, reporter, broker.TTLDefaulter(logger, int32(env.MaxTTL)), brokerInformer, oidcTokenVerifier, oidcTokenProvider, trustBundleConfigMapInformer, ctxFunc) if err != nil { diff --git a/cmd/jobsink/main.go b/cmd/jobsink/main.go index 0f8c99646b4..02c564feea0 100644 --- a/cmd/jobsink/main.go +++ b/cmd/jobsink/main.go @@ -103,8 +103,13 @@ func main() { logger.Info("Starting the JobSink Ingress") + var h *Handler + featureStore := feature.NewStore(logging.FromContext(ctx).Named("feature-config-store"), func(name string, value interface{}) { logger.Info("Updated", zap.String("name", name), zap.Any("value", value)) + if flags, ok := value.(feature.Flags); ok && h != nil { + h.oidcTokenVerifier = auth.NewOIDCTokenVerifier(ctx, flags) + } }) featureStore.WatchConfigs(configMapWatcher) @@ -113,11 +118,11 @@ func main() { return logging.WithLogger(featureStore.ToContext(ctx), sl) } - h := &Handler{ + h = &Handler{ k8s: kubeclient.Get(ctx), lister: jobsink.Get(ctx).Lister(), withContext: ctxFunc, - oidcTokenVerifier: auth.NewOIDCTokenVerifier(ctx), + oidcTokenVerifier: auth.NewOIDCTokenVerifier(ctx, featureStore.Load()), } tlsConfig, err := getServerTLSConfig(ctx) diff --git a/pkg/apis/feature/features.go b/pkg/apis/feature/features.go index b2ca380fc77..98eeb2907ca 100644 --- a/pkg/apis/feature/features.go +++ b/pkg/apis/feature/features.go @@ -64,6 +64,9 @@ const ( // This configuration is applied when there is no EventPolicy with a "to" referencing a given // resource. AuthorizationAllowSameNamespace Flag = "Allow-Same-Namespace" + + // DefaultOIDCDiscoveryURL is the default OIDC Discovery URL used in most Kubernetes clusters. + DefaultOIDCDiscoveryBaseURL Flag = "https://kubernetes.default.svc" ) // Flags is a map containing all the enabled/disabled flags for the experimental features. @@ -81,6 +84,7 @@ func newDefaults() Flags { EvenTypeAutoCreate: Disabled, NewAPIServerFilters: Disabled, AuthorizationDefaultMode: AuthorizationAllowSameNamespace, + OIDCDiscoveryBaseURL: DefaultOIDCDiscoveryBaseURL, } } @@ -134,6 +138,19 @@ func (e Flags) IsAuthorizationDefaultModeSameNamespace() bool { return e != nil && e[AuthorizationDefaultMode] == AuthorizationAllowSameNamespace } +func (e Flags) OIDCDiscoveryBaseURL() string { + if e == nil { + return string(DefaultOIDCDiscoveryBaseURL) + } + + discoveryUrl, ok := e[OIDCDiscoveryBaseURL] + if !ok { + return string(DefaultOIDCDiscoveryBaseURL) + } + + return string(discoveryUrl) +} + func (e Flags) String() string { return fmt.Sprintf("%+v", map[string]Flag(e)) } @@ -183,7 +200,7 @@ func NewFlagsConfigFromMap(data map[string]string) (Flags, error) { flags[sanitizedKey] = AuthorizationDenyAll } else if sanitizedKey == AuthorizationDefaultMode && strings.EqualFold(v, string(AuthorizationAllowSameNamespace)) { flags[sanitizedKey] = AuthorizationAllowSameNamespace - } else if strings.Contains(k, NodeSelectorLabel) { + } else if strings.Contains(k, NodeSelectorLabel) || sanitizedKey == OIDCDiscoveryBaseURL { flags[sanitizedKey] = Flag(v) } else { flags[k] = Flag(v) diff --git a/pkg/apis/feature/features_test.go b/pkg/apis/feature/features_test.go index 5b7caa8404a..34d899d2209 100644 --- a/pkg/apis/feature/features_test.go +++ b/pkg/apis/feature/features_test.go @@ -61,6 +61,8 @@ func TestGetFlags(t *testing.T) { nodeSelector := flags.NodeSelector() expectedNodeSelector := map[string]string{"testkey": "testvalue", "testkey1": "testvalue1", "testkey2": "testvalue2"} require.Equal(t, expectedNodeSelector, nodeSelector) + + require.Equal(t, flags.OIDCDiscoveryBaseURL(), "https://oidc.eks.eu-west-1.amazonaws.com/id/1") } func TestShouldNotOverrideDefaults(t *testing.T) { diff --git a/pkg/apis/feature/flag_names.go b/pkg/apis/feature/flag_names.go index 6a7579fb710..e21056eb444 100644 --- a/pkg/apis/feature/flag_names.go +++ b/pkg/apis/feature/flag_names.go @@ -28,4 +28,5 @@ const ( CrossNamespaceEventLinks = "cross-namespace-event-links" NewAPIServerFilters = "new-apiserversource-filters" AuthorizationDefaultMode = "default-authorization-mode" + OIDCDiscoveryBaseURL = "oidc-discovery-base-url" ) diff --git a/pkg/apis/feature/testdata/config-features.yaml b/pkg/apis/feature/testdata/config-features.yaml index 6c3252ba429..bebbfea4b79 100644 --- a/pkg/apis/feature/testdata/config-features.yaml +++ b/pkg/apis/feature/testdata/config-features.yaml @@ -29,3 +29,4 @@ data: apiserversources-nodeselector-testkey: testvalue apiserversources-nodeselector-testkey1: testvalue1 apiserversources-nodeselector-testkey2: testvalue2 + oidc-discovery-base-url: "https://oidc.eks.eu-west-1.amazonaws.com/id/1" diff --git a/pkg/auth/token_verifier.go b/pkg/auth/token_verifier.go index 0d87cf11f69..2bf4855b7fa 100644 --- a/pkg/auth/token_verifier.go +++ b/pkg/auth/token_verifier.go @@ -37,10 +37,6 @@ import ( "knative.dev/pkg/logging" ) -const ( - kubernetesOIDCDiscoveryBaseURL = "https://kubernetes.default.svc" -) - type OIDCTokenVerifier struct { logger *zap.SugaredLogger restConfig *rest.Config @@ -57,14 +53,14 @@ type IDToken struct { AccessTokenHash string } -func NewOIDCTokenVerifier(ctx context.Context) *OIDCTokenVerifier { +func NewOIDCTokenVerifier(ctx context.Context, features feature.Flags) *OIDCTokenVerifier { tokenHandler := &OIDCTokenVerifier{ logger: logging.FromContext(ctx).With("component", "oidc-token-handler"), restConfig: injection.GetConfig(ctx), eventPolicyLister: eventpolicyinformer.Get(ctx).Lister(), } - if err := tokenHandler.initOIDCProvider(ctx); err != nil { + if err := tokenHandler.initOIDCProvider(ctx, features); err != nil { tokenHandler.logger.Error(fmt.Sprintf("could not initialize provider. You can ignore this message, when the %s feature is disabled", feature.OIDCAuthentication), zap.Error(err)) } @@ -186,13 +182,13 @@ func (v *OIDCTokenVerifier) verifyJWT(ctx context.Context, jwt, audience string) }, nil } -func (v *OIDCTokenVerifier) initOIDCProvider(ctx context.Context) error { - discovery, err := v.getKubernetesOIDCDiscovery() +func (v *OIDCTokenVerifier) initOIDCProvider(ctx context.Context, features feature.Flags) error { + discovery, err := v.getKubernetesOIDCDiscovery(features) if err != nil { return fmt.Errorf("could not load Kubernetes OIDC discovery information: %w", err) } - if discovery.Issuer != kubernetesOIDCDiscoveryBaseURL { + if discovery.Issuer != features.OIDCDiscoveryBaseURL() { // in case we have another issuer as the api server: ctx = oidc.InsecureIssuerURLContext(ctx, discovery.Issuer) } @@ -204,7 +200,7 @@ func (v *OIDCTokenVerifier) initOIDCProvider(ctx context.Context) error { ctx = oidc.ClientContext(ctx, httpClient) // get OIDC provider - v.provider, err = oidc.NewProvider(ctx, kubernetesOIDCDiscoveryBaseURL) + v.provider, err = oidc.NewProvider(ctx, features.OIDCDiscoveryBaseURL()) if err != nil { return fmt.Errorf("could not get OIDC provider: %w", err) } @@ -223,13 +219,13 @@ func (v *OIDCTokenVerifier) getHTTPClientForKubeAPIServer() (*http.Client, error return client, nil } -func (v *OIDCTokenVerifier) getKubernetesOIDCDiscovery() (*openIDMetadata, error) { +func (v *OIDCTokenVerifier) getKubernetesOIDCDiscovery(features feature.Flags) (*openIDMetadata, error) { client, err := v.getHTTPClientForKubeAPIServer() if err != nil { return nil, fmt.Errorf("could not get HTTP client for API server: %w", err) } - resp, err := client.Get(kubernetesOIDCDiscoveryBaseURL + "/.well-known/openid-configuration") + resp, err := client.Get(features.OIDCDiscoveryBaseURL() + "/.well-known/openid-configuration") if err != nil { return nil, fmt.Errorf("could not get response: %w", err) } diff --git a/pkg/broker/filter/filter_handler.go b/pkg/broker/filter/filter_handler.go index 8ea2565ebfa..c795217e3c0 100644 --- a/pkg/broker/filter/filter_handler.go +++ b/pkg/broker/filter/filter_handler.go @@ -84,7 +84,7 @@ type Handler struct { logger *zap.Logger withContext func(ctx context.Context) context.Context filtersMap *subscriptionsapi.FiltersMap - tokenVerifier *auth.OIDCTokenVerifier + TokenVerifier *auth.OIDCTokenVerifier EventTypeCreator *eventtype.EventTypeAutoHandler } @@ -146,7 +146,7 @@ func NewHandler(logger *zap.Logger, tokenVerifier *auth.OIDCTokenVerifier, oidcT triggerLister: triggerInformer.Lister(), brokerLister: brokerInformer.Lister(), logger: logger, - tokenVerifier: tokenVerifier, + TokenVerifier: tokenVerifier, withContext: wc, filtersMap: fm, }, nil @@ -204,7 +204,7 @@ func (h *Handler) ServeHTTP(writer http.ResponseWriter, request *http.Request) { audience := FilterAudience - err = h.tokenVerifier.VerifyJWTFromRequest(ctx, request, &audience, writer) + err = h.TokenVerifier.VerifyJWTFromRequest(ctx, request, &audience, writer) if err != nil { h.logger.Warn("Error when validating the JWT token in the request", zap.Error(err)) return diff --git a/pkg/broker/filter/filter_handler_test.go b/pkg/broker/filter/filter_handler_test.go index e220e401774..2e0112ee4da 100644 --- a/pkg/broker/filter/filter_handler_test.go +++ b/pkg/broker/filter/filter_handler_test.go @@ -439,7 +439,7 @@ func TestReceiver(t *testing.T) { logger := zaptest.NewLogger(t, zaptest.WrapOptions(zap.AddCaller())) oidcTokenProvider := auth.NewOIDCTokenProvider(ctx) - oidcTokenVerifier := auth.NewOIDCTokenVerifier(ctx) + oidcTokenVerifier := auth.NewOIDCTokenVerifier(ctx, feature.FromContext(ctx)) for _, trig := range tc.triggers { // Replace the SubscriberURI to point at our fake server. @@ -638,7 +638,7 @@ func TestReceiver_WithSubscriptionsAPI(t *testing.T) { logger := zaptest.NewLogger(t, zaptest.WrapOptions(zap.AddCaller())) oidcTokenProvider := auth.NewOIDCTokenProvider(ctx) - oidcTokenVerifier := auth.NewOIDCTokenVerifier(ctx) + oidcTokenVerifier := auth.NewOIDCTokenVerifier(ctx, feature.FromContextOrDefaults(ctx)) // Replace the SubscriberURI to point at our fake server. for _, trig := range tc.triggers { diff --git a/pkg/broker/ingress/ingress_handler.go b/pkg/broker/ingress/ingress_handler.go index 36f514c0cc6..eeadb2b328d 100644 --- a/pkg/broker/ingress/ingress_handler.go +++ b/pkg/broker/ingress/ingress_handler.go @@ -73,7 +73,7 @@ type Handler struct { eventDispatcher *kncloudevents.Dispatcher - tokenVerifier *auth.OIDCTokenVerifier + TokenVerifier *auth.OIDCTokenVerifier withContext func(ctx context.Context) context.Context } @@ -128,7 +128,7 @@ func NewHandler(logger *zap.Logger, reporter StatsReporter, defaulter client.Eve Logger: logger, BrokerLister: brokerInformer.Lister(), eventDispatcher: kncloudevents.NewDispatcher(clientConfig, oidcTokenProvider), - tokenVerifier: tokenVerifier, + TokenVerifier: tokenVerifier, withContext: withContext, }, nil } @@ -237,7 +237,7 @@ func (h *Handler) ServeHTTP(writer http.ResponseWriter, request *http.Request) { if broker.Status.Address != nil { audience = broker.Status.Address.Audience } - err = h.tokenVerifier.VerifyRequest(ctx, features, audience, brokerNamespace, broker.Status.Policies, request, writer) + err = h.TokenVerifier.VerifyRequest(ctx, features, audience, brokerNamespace, broker.Status.Policies, request, writer) if err != nil { h.Logger.Warn("Failed to verify AuthN and AuthZ.", zap.Error(err)) return diff --git a/pkg/broker/ingress/ingress_handler_test.go b/pkg/broker/ingress/ingress_handler_test.go index db6a18dda4c..5b5a6095226 100644 --- a/pkg/broker/ingress/ingress_handler_test.go +++ b/pkg/broker/ingress/ingress_handler_test.go @@ -40,6 +40,7 @@ import ( "knative.dev/eventing/pkg/apis/eventing" eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" + "knative.dev/eventing/pkg/apis/feature" "knative.dev/eventing/pkg/auth" "knative.dev/eventing/pkg/broker" @@ -290,7 +291,7 @@ func TestHandler_ServeHTTP(t *testing.T) { } tokenProvider := auth.NewOIDCTokenProvider(ctx) - tokenVerifier := auth.NewOIDCTokenVerifier(ctx) + tokenVerifier := auth.NewOIDCTokenVerifier(ctx, feature.FromContextOrDefaults(ctx)) h, err := NewHandler(logger, &mockReporter{}, diff --git a/pkg/reconciler/inmemorychannel/dispatcher/controller.go b/pkg/reconciler/inmemorychannel/dispatcher/controller.go index fbe1cd4fde3..5a048c537dc 100644 --- a/pkg/reconciler/inmemorychannel/dispatcher/controller.go +++ b/pkg/reconciler/inmemorychannel/dispatcher/controller.go @@ -129,6 +129,15 @@ func NewController( TrustBundleConfigMapLister: trustBundleConfigMapInformer.Lister().ConfigMaps(system.Namespace()), } + var globalResync func(obj interface{}) + + featureStore := feature.NewStore(logging.FromContext(ctx).Named("feature-config-store"), func(_ string, _ interface{}) { + if globalResync != nil { + globalResync(nil) + } + }) + + featureStore.WatchConfigs(cmw) r := &Reconciler{ multiChannelEventHandler: sh, reporter: reporter, @@ -136,24 +145,16 @@ func NewController( eventingClient: eventingclient.Get(ctx).EventingV1beta2(), eventTypeLister: eventtypeinformer.Get(ctx).Lister(), eventDispatcher: kncloudevents.NewDispatcher(clientConfig, oidcTokenProvider), - tokenVerifier: auth.NewOIDCTokenVerifier(ctx), + tokenVerifier: auth.NewOIDCTokenVerifier(ctx, featureStore.Load()), clientConfig: clientConfig, } - var globalResync func(obj interface{}) - - featureStore := feature.NewStore(logging.FromContext(ctx).Named("feature-config-store"), func(_ string, _ interface{}) { - if globalResync != nil { - globalResync(nil) - } - }) - featureStore.WatchConfigs(cmw) - impl := inmemorychannelreconciler.NewImpl(ctx, r, func(impl *controller.Impl) controller.Options { return controller.Options{SkipStatusUpdates: true, FinalizerName: finalizerName, ConfigStore: featureStore} }) globalResync = func(_ interface{}) { + r.tokenVerifier = auth.NewOIDCTokenVerifier(ctx, featureStore.Load()) impl.GlobalResync(inmemorychannelInformer.Informer()) }