58237d0e7d
This commit includes a failing test (amongst other compiler failures) for the dynamic signing key fetcher that we will inject into fosite. We are checking it in so that we can pass the WIP off. Signed-off-by: Margo Crawford <margaretc@vmware.com>
115 lines
3.8 KiB
Go
115 lines
3.8 KiB
Go
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package supervisorconfig
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"gopkg.in/square/go-jose.v2"
|
|
"k8s.io/apimachinery/pkg/labels"
|
|
corev1informers "k8s.io/client-go/informers/core/v1"
|
|
|
|
"go.pinniped.dev/generated/1.19/client/supervisor/informers/externalversions/config/v1alpha1"
|
|
pinnipedcontroller "go.pinniped.dev/internal/controller"
|
|
"go.pinniped.dev/internal/controllerlib"
|
|
"go.pinniped.dev/internal/plog"
|
|
)
|
|
|
|
type jwksObserverController struct {
|
|
issuerToJWKSSetter IssuerToJWKSMapSetter
|
|
oidcProviderInformer v1alpha1.OIDCProviderInformer
|
|
secretInformer corev1informers.SecretInformer
|
|
}
|
|
|
|
type IssuerToJWKSMapSetter interface {
|
|
SetIssuerToJWKSMap(
|
|
issuerToJWKSMap map[string]*jose.JSONWebKeySet,
|
|
issuerToActiveJWKMap map[string]*jose.JSONWebKey,
|
|
)
|
|
}
|
|
|
|
// Returns a controller which watches all of the OIDCProviders and their corresponding Secrets
|
|
// and fills an in-memory cache of the JWKS info for each currently configured issuer.
|
|
// This controller assumes that the informers passed to it are already scoped down to the
|
|
// appropriate namespace. It also assumes that the IssuerToJWKSMapSetter passed to it has an
|
|
// underlying implementation which is thread-safe.
|
|
func NewJWKSObserverController(
|
|
issuerToJWKSSetter IssuerToJWKSMapSetter,
|
|
secretInformer corev1informers.SecretInformer,
|
|
oidcProviderInformer v1alpha1.OIDCProviderInformer,
|
|
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
|
) controllerlib.Controller {
|
|
return controllerlib.New(
|
|
controllerlib.Config{
|
|
Name: "jwks-observer-controller",
|
|
Syncer: &jwksObserverController{
|
|
issuerToJWKSSetter: issuerToJWKSSetter,
|
|
oidcProviderInformer: oidcProviderInformer,
|
|
secretInformer: secretInformer,
|
|
},
|
|
},
|
|
withInformer(
|
|
secretInformer,
|
|
pinnipedcontroller.MatchAnythingFilter(nil),
|
|
controllerlib.InformerOption{},
|
|
),
|
|
withInformer(
|
|
oidcProviderInformer,
|
|
pinnipedcontroller.MatchAnythingFilter(nil),
|
|
controllerlib.InformerOption{},
|
|
),
|
|
)
|
|
}
|
|
|
|
func (c *jwksObserverController) Sync(ctx controllerlib.Context) error {
|
|
ns := ctx.Key.Namespace
|
|
allProviders, err := c.oidcProviderInformer.Lister().OIDCProviders(ns).List(labels.Everything())
|
|
if err != nil {
|
|
return fmt.Errorf("failed to list OIDCProviders: %w", err)
|
|
}
|
|
|
|
// Rebuild the whole map on any change to any Secret or OIDCProvider, because either can have changes that
|
|
// can cause the map to need to be updated.
|
|
issuerToJWKSMap := map[string]*jose.JSONWebKeySet{}
|
|
issuerToActiveJWKMap := map[string]*jose.JSONWebKey{}
|
|
|
|
for _, provider := range allProviders {
|
|
secretRef := provider.Status.JWKSSecret
|
|
jwksSecret, err := c.secretInformer.Lister().Secrets(ns).Get(secretRef.Name)
|
|
if err != nil {
|
|
plog.Debug("jwksObserverController Sync could not find JWKS secret", "namespace", ns, "secretName", secretRef.Name)
|
|
continue
|
|
}
|
|
|
|
jwksFromSecret := jose.JSONWebKeySet{}
|
|
err = json.Unmarshal(jwksSecret.Data[jwksKey], &jwksFromSecret)
|
|
if err != nil {
|
|
plog.Debug("jwksObserverController Sync found a JWKS secret with Data in an unexpected format", "namespace", ns, "secretName", secretRef.Name)
|
|
continue
|
|
}
|
|
|
|
activeJWKFromSecret := jose.JSONWebKey{}
|
|
err = json.Unmarshal(jwksSecret.Data[activeJWKKey], &activeJWKFromSecret)
|
|
if err != nil {
|
|
plog.Debug("jwksObserverController Sync found an active JWK secret with Data in an unexpected format", "namespace", ns, "secretName", secretRef.Name)
|
|
continue
|
|
}
|
|
|
|
issuerToJWKSMap[provider.Spec.Issuer] = &jwksFromSecret
|
|
issuerToActiveJWKMap[provider.Spec.Issuer] = &activeJWKFromSecret
|
|
}
|
|
|
|
plog.Debug(
|
|
"jwksObserverController Sync updated the JWKS cache",
|
|
"issuerJWKSCount",
|
|
len(issuerToJWKSMap),
|
|
"issuerActiveJWKCount",
|
|
len(issuerToActiveJWKMap),
|
|
)
|
|
c.issuerToJWKSSetter.SetIssuerToJWKSMap(issuerToJWKSMap, issuerToActiveJWKMap)
|
|
|
|
return nil
|
|
}
|