From 7e514210b0964e8edb7c28d6ae41b1ed19b66513 Mon Sep 17 00:00:00 2001 From: Julio Camarero Date: Mon, 9 Dec 2024 17:11:20 +0100 Subject: [PATCH] sync certs when ingress/secrets/configmaps are created/updated/deleted --- internal/ingress/controller/store/store.go | 135 +++++++++++++++++++-- 1 file changed, 127 insertions(+), 8 deletions(-) diff --git a/internal/ingress/controller/store/store.go b/internal/ingress/controller/store/store.go index 17ac371fd..8c575801c 100644 --- a/internal/ingress/controller/store/store.go +++ b/internal/ingress/controller/store/store.go @@ -22,6 +22,7 @@ import ( "fmt" "os" "reflect" + "slices" "sort" "strings" "sync" @@ -36,6 +37,7 @@ import ( "k8s.io/apimachinery/pkg/labels" k8sruntime "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/informers" clientset "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/scheme" @@ -475,7 +477,9 @@ func New( store.updateSecretIngressMap(ing) store.syncSecrets(ing) store.updateClientCertSecretIngressMap(ing) + store.syncClientCertSecrets(ing) store.updateCAConfigMapIngressMap(ing) + store.syncCAConfigMaps(ing) updateCh.In() <- Event{ Type: CreateEvent, @@ -534,7 +538,9 @@ func New( store.updateSecretIngressMap(curIng) store.syncSecrets(curIng) store.updateClientCertSecretIngressMap(curIng) + store.syncClientCertSecrets(curIng) store.updateCAConfigMapIngressMap(curIng) + store.syncCAConfigMaps(curIng) updateCh.In() <- Event{ Type: UpdateEvent, @@ -629,9 +635,9 @@ func New( store.syncSecret(store.defaultSSLCertificate) } - // find references in ingresses and update local ssl certs + // find references in ingresses for SSL secret and update local ssl certs if ings := store.secretIngressMap.Reference(key); len(ings) > 0 { - klog.InfoS("Secret was added and it is used in ingress annotations. Parsing", "secret", key) + klog.InfoS("SSL Secret was added and it is used in ingress annotations. Parsing", "secret", key) for _, ingKey := range ings { ing, err := store.getIngress(ingKey) if err != nil { @@ -646,6 +652,24 @@ func New( Obj: obj, } } + + // find references in ingresses for client cert secret and update local ssl certs + if ings := store.clientCertSecretIngressMap.Reference(key); len(ings) > 0 { + klog.InfoS("Client cert Secret was added and it is used in ingress annotations. Parsing", "secret", key) + for _, ingKey := range ings { + ing, err := store.getIngress(ingKey) + if err != nil { + klog.Errorf("could not find Ingress %v in local store", ingKey) + continue + } + store.syncIngress(ing) + store.syncClientCertSecret(key) + } + updateCh.In() <- Event{ + Type: CreateEvent, + Obj: obj, + } + } }, UpdateFunc: func(old, cur interface{}) { if !reflect.DeepEqual(old, cur) { @@ -663,9 +687,9 @@ func New( store.syncSecret(store.defaultSSLCertificate) } - // find references in ingresses and update local ssl certs + // find references in ingresses for SSL secret and update local ssl certs if ings := store.secretIngressMap.Reference(key); len(ings) > 0 { - klog.InfoS("secret was updated and it is used in ingress annotations. Parsing", "secret", key) + klog.InfoS("SSL secret was updated and it is used in ingress annotations. Parsing", "secret", key) for _, ingKey := range ings { ing, err := store.getIngress(ingKey) if err != nil { @@ -680,6 +704,24 @@ func New( Obj: cur, } } + + // find references in ingresses for SSL client secret and update local ssl certs + if ings := store.clientCertSecretIngressMap.Reference(key); len(ings) > 0 { + klog.InfoS("client cert secret was updated and it is used in ingress annotations. Parsing", "secret", key) + for _, ingKey := range ings { + ing, err := store.getIngress(ingKey) + if err != nil { + klog.ErrorS(err, "could not find Ingress in local store", "ingress", ingKey) + continue + } + store.syncClientCertSecret(key) + store.syncIngress(ing) + } + updateCh.In() <- Event{ + Type: UpdateEvent, + Obj: cur, + } + } } }, DeleteFunc: func(obj interface{}) { @@ -706,9 +748,11 @@ func New( key := k8s.MetaNamespaceKey(sec) // find references in ingresses - if ings := store.secretIngressMap.Reference(key); len(ings) > 0 { + ings := sets.New(store.secretIngressMap.Reference(key)...) + ings.Insert(store.clientCertSecretIngressMap.Reference(key)...) + if ings.Len() > 0 { klog.InfoS("secret was deleted and it is used in ingress annotations. Parsing", "secret", key) - for _, ingKey := range ings { + for _, ingKey := range ings.UnsortedList() { ing, err := store.getIngress(ingKey) if err != nil { klog.Errorf("could not find Ingress %v in local store", ingKey) @@ -760,18 +804,20 @@ func New( return name == configmap || name == tcp || name == udp } - handleCfgMapEvent := func(key string, cfgMap *corev1.ConfigMap, eventName string) { + handleCfgMapEvent := func(key string, cfgMap *corev1.ConfigMap, event EventType) { // updates to configuration configmaps can trigger an update triggerUpdate := false if changeTriggerUpdate(key) { triggerUpdate = true - recorder.Eventf(cfgMap, corev1.EventTypeNormal, eventName, fmt.Sprintf("ConfigMap %v", key)) + recorder.Eventf(cfgMap, corev1.EventTypeNormal, string(event), fmt.Sprintf("ConfigMap %v", key)) if key == configmap { store.setConfig(cfgMap) } } ings := store.listers.IngressWithAnnotation.List() + ingRefCM := store.caConfigMapIngressMap.Reference(key) + for _, ingKey := range ings { key := k8s.MetaNamespaceKey(ingKey) ing, err := store.getIngress(key) @@ -780,6 +826,19 @@ func New( continue } + if slices.Contains(ingRefCM, key) { + klog.InfoS("ca config map was updated and it is used in ingress annotations. Parsing", "configmap", key) + cmKey := k8s.MetaNamespaceKey(configmap) + + store.syncCAConfigMap(cmKey) + store.syncIngress(ing) + updateCh.In() <- Event{ + Type: event, + Obj: cfgMap, + } + continue + } + if parser.AnnotationsReferencesConfigmap(ing) { store.syncIngress(ing) continue @@ -819,6 +878,48 @@ func New( key := k8s.MetaNamespaceKey(cfgMap) handleCfgMapEvent(key, cfgMap, "UPDATE") }, + DeleteFunc: func(obj interface{}) { + cfgMap, ok := obj.(*corev1.ConfigMap) + + if !ok { + // If we reached here it means the configmap was deleted but its final state is unrecorded. + tombstone, ok := obj.(cache.DeletedFinalStateUnknown) + if !ok { + return + } + + cfgMap, ok = tombstone.Obj.(*corev1.ConfigMap) + if !ok { + return + } + } + + if !watchedNamespace(cfgMap.Namespace) { + return + } + + store.sslStore.Delete(k8s.MetaNamespaceKey(cfgMap)) + + key := k8s.MetaNamespaceKey(cfgMap) + + // find references in ingresses + if ings := store.caConfigMapIngressMap.Reference(key); len(ings) > 0 { + klog.InfoS("configmap was deleted and it is used in ingress annotations. Parsing", "configMap", key) + for _, ingKey := range ings { + ing, err := store.getIngress(ingKey) + if err != nil { + klog.Errorf("could not find Ingress %v in local store", ingKey) + continue + } + store.syncIngress(ing) + } + + updateCh.In() <- Event{ + Type: DeleteEvent, + Obj: obj, + } + } + }, } serviceHandler := cache.ResourceEventHandlerFuncs{ @@ -1098,6 +1199,24 @@ func (s *k8sStore) syncSecrets(ing *networkingv1.Ingress) { } } +// syncClientCertSecrets synchronizes data from client cert Secrets referenced by the given +// Ingress with the local store and file system. +func (s *k8sStore) syncClientCertSecrets(ing *networkingv1.Ingress) { + key := k8s.MetaNamespaceKey(ing) + for _, secrKey := range s.clientCertSecretIngressMap.ReferencedBy(key) { + s.syncClientCertSecret(secrKey) + } +} + +// syncCAConfigMaps synchronizes data from CA configmaps referenced by the given +// Ingress with the local store and file system. +func (s *k8sStore) syncCAConfigMaps(ing *networkingv1.Ingress) { + key := k8s.MetaNamespaceKey(ing) + for _, cmKey := range s.caConfigMapIngressMap.ReferencedBy(key) { + s.syncCAConfigMap(cmKey) + } +} + // GetSecret returns the Secret matching key. func (s *k8sStore) GetSecret(key string) (*corev1.Secret, error) { return s.listers.Secret.ByKey(key)