From ae372cd321d36ae64b20aa4a901f88894d3b5ed0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Ma=C5=82ek?= Date: Fri, 13 Dec 2024 17:40:32 +0100 Subject: [PATCH] feat(backendtlspolicy): enqueue for ConfigMaps (#6837) --- CHANGELOG.md | 1 + .../gateway/backendtlspolicy_controller.go | 54 +++++++++++++ .../gateway/backendtlspolicy_utils.go | 16 ++++ .../gateway/backendtlspolicy_utils_test.go | 77 +++++++++++++++++++ 4 files changed, 148 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3120fcdb9f..6b8d8de6b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -251,6 +251,7 @@ Adding a new version? You'll need three changes: is applied to the service section of the Kong configuration. [#6712](https://github.com/Kong/kubernetes-ingress-controller/pull/6712) [#6753](https://github.com/Kong/kubernetes-ingress-controller/pull/6753) + [#6837](https://github.com/Kong/kubernetes-ingress-controller/pull/6837) - Added the flag `--configmap-label-selector` to set the label selector for `ConfigMap`s to ingest. By setting this flag, the `ConfigMap`s that are ingested will be limited to those having this label set to "true". This limits the amount of resources that are kept in memory. diff --git a/internal/controllers/gateway/backendtlspolicy_controller.go b/internal/controllers/gateway/backendtlspolicy_controller.go index 91e843b65a..482d306fed 100644 --- a/internal/controllers/gateway/backendtlspolicy_controller.go +++ b/internal/controllers/gateway/backendtlspolicy_controller.go @@ -54,6 +54,7 @@ func (r *BackendTLSPolicyReconciler) SetupWithManager(mgr ctrl.Manager) error { CacheSyncTimeout: r.CacheSyncTimeout, }). For(&gatewayapi.BackendTLSPolicy{}). + Watches(&corev1.ConfigMap{}, handler.EnqueueRequestsFromMapFunc(r.listBackendTLSPoliciesForConfigMaps)). Watches(&corev1.Service{}, handler.EnqueueRequestsFromMapFunc(r.listBackendTLSPoliciesForServices)). Watches(&gatewayapi.HTTPRoute{}, handler.EnqueueRequestsFromMapFunc(r.listBackendTLSPoliciesForHTTPRoutes)). Watches(&gatewayapi.Gateway{}, handler.EnqueueRequestsFromMapFunc(r.listBackendTLSPoliciesForGateways)). @@ -65,6 +66,9 @@ func (r *BackendTLSPolicyReconciler) SetupWithManager(mgr ctrl.Manager) error { // ----------------------------------------------------------------------------- const ( + // backendTLSPolicyValidationCARefIndexKey is the index key for BackendTLSPolicy objects by their validation CA configmap reference. + // The value is the name of the configmap. + backendTLSPolicyValidationCARefIndexKey = "backendtlspolicy-validation-cacertificateref" // backendTLSPolicyTargetRefIndexKey is the index key for BackendTLSPolicy objects by their target service reference. // The value is the name of the service. backendTLSPolicyTargetRefIndexKey = "backendtlspolicy-targetref" @@ -92,6 +96,23 @@ func indexBackendTLSPolicyOnTargetRef(obj client.Object) []string { return services } +// indexBackendTLSPolicyOnValidationCACertificateRef indexes BackendTLSPolicy objects +// by their validation CA Certificate configmap reference. +func indexBackendTLSPolicyOnValidationCACertificateRef(obj client.Object) []string { + policy, ok := obj.(*gatewayapi.BackendTLSPolicy) + if !ok { + return []string{} + } + + configmaps := []string{} + for _, cacertref := range policy.Spec.Validation.CACertificateRefs { + if (cacertref.Group == "" || cacertref.Group == "core") && cacertref.Kind == "ConfigMap" { + configmaps = append(configmaps, string(cacertref.Name)) + } + } + return configmaps +} + // indexHTTPRouteOnParentRef indexes HTTPRoute objects by their parent Gateway references. func indexHTTPRouteOnParentRef(obj client.Object) []string { httpRoute, ok := obj.(*gatewayapi.HTTPRoute) @@ -148,6 +169,15 @@ func setupBackendTLSPolicyIndices(mgr ctrl.Manager) error { return fmt.Errorf("failed to index backendTLSPolicies on service reference: %w", err) } + if err := mgr.GetCache().IndexField( + context.Background(), + &gatewayapi.BackendTLSPolicy{}, + backendTLSPolicyValidationCARefIndexKey, + indexBackendTLSPolicyOnValidationCACertificateRef, + ); err != nil { + return fmt.Errorf("failed to index backendTLSPolicies on validation CA configmap reference: %w", err) + } + if err := mgr.GetCache().IndexField( context.Background(), &gatewayapi.HTTPRoute{}, @@ -173,6 +203,30 @@ func setupBackendTLSPolicyIndices(mgr ctrl.Manager) error { // BackendTLSPolicy Controller - Event Handlers // ----------------------------------------------------------------------------- +// listBackendTLSPoliciesForConfigMaps returns the list of BackendTLSPolicies that targets the given ConfigMap. +func (r *BackendTLSPolicyReconciler) listBackendTLSPoliciesForConfigMaps(ctx context.Context, obj client.Object) []reconcile.Request { + cm, ok := obj.(*corev1.ConfigMap) + if !ok { + r.Log.Error(fmt.Errorf("invalid type"), "Found invalid type in event handlers", "expected", "ConfigMap", "found", reflect.TypeOf(obj)) + return nil + } + policies := &gatewayapi.BackendTLSPolicyList{} + if err := r.List(ctx, policies, + client.InNamespace(cm.Namespace), + client.MatchingFields{backendTLSPolicyValidationCARefIndexKey: cm.Name}, + ); err != nil { + r.Log.Error(err, "Failed to list BackendTLSPolicies for ConfigMap", "configmap", cm) + return nil + } + requests := make([]reconcile.Request, 0, len(policies.Items)) + for _, policy := range policies.Items { + requests = append(requests, reconcile.Request{ + NamespacedName: client.ObjectKeyFromObject(&policy), + }) + } + return requests +} + // listBackendTLSPoliciesForServices returns the list of BackendTLSPolicies that targets the given Service. func (r *BackendTLSPolicyReconciler) listBackendTLSPoliciesForServices(ctx context.Context, obj client.Object) []reconcile.Request { service, ok := obj.(*corev1.Service) diff --git a/internal/controllers/gateway/backendtlspolicy_utils.go b/internal/controllers/gateway/backendtlspolicy_utils.go index bd465a1e9a..739852d129 100644 --- a/internal/controllers/gateway/backendtlspolicy_utils.go +++ b/internal/controllers/gateway/backendtlspolicy_utils.go @@ -2,10 +2,12 @@ package gateway import ( "context" + "fmt" "sort" "strings" "github.com/samber/lo" + corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" k8stypes "k8s.io/apimachinery/pkg/types" @@ -240,6 +242,20 @@ func (r *BackendTLSPolicyReconciler) validateBackendTLSPolicy(ctx context.Contex invalidMessages = append(invalidMessages, "CACertificateRefs must reference ConfigMaps in the core group") break } + + var ( + cm corev1.ConfigMap + configMapNN = k8stypes.NamespacedName{ + Namespace: policy.Namespace, + Name: string(caCert.Name), + } + ) + if err := r.Get(ctx, configMapNN, &cm); err != nil { + invalidMessages = append(invalidMessages, + fmt.Sprintf("failed getting ConfigMap %s set as CACertificateRef: %s", configMapNN, err), + ) + break + } } if len(policy.Spec.Validation.SubjectAltNames) > 0 { invalidMessages = append(invalidMessages, "SubjectAltNames feature is not currently supported") diff --git a/internal/controllers/gateway/backendtlspolicy_utils_test.go b/internal/controllers/gateway/backendtlspolicy_utils_test.go index 6081e8b77f..f941db95d6 100644 --- a/internal/controllers/gateway/backendtlspolicy_utils_test.go +++ b/internal/controllers/gateway/backendtlspolicy_utils_test.go @@ -10,6 +10,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" k8stypes "k8s.io/apimachinery/pkg/types" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" @@ -764,9 +765,80 @@ func TestValidateBackendTLSPolicy(t *testing.T) { Message: "CACertificateRefs must reference ConfigMaps in the core group - SubjectAltNames feature is not currently supported - WellKnownCACertificates feature is not currently supported", }, }, + { + name: "valid policy referencing not existing CACert (ConfigMap)", + policy: &gatewayapi.BackendTLSPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-policy", + Namespace: "default", + }, + Spec: gatewayapi.BackendTLSPolicySpec{ + TargetRefs: []gatewayapi.LocalPolicyTargetReferenceWithSectionName{ + { + LocalPolicyTargetReference: gatewayapi.LocalPolicyTargetReference{ + Group: "core", + Kind: "Service", + Name: "example-service", + }, + }, + }, + Validation: gatewayapi.BackendTLSPolicyValidation{ + CACertificateRefs: []gatewayapi.LocalObjectReference{ + { + Group: "", + Kind: "ConfigMap", + Name: gatewayapi.ObjectName("example-configmap"), + }, + }, + }, + }, + }, + expected: &metav1.Condition{ + Type: string(gatewayapi.PolicyConditionAccepted), + Status: metav1.ConditionFalse, + Reason: string(gatewayapi.PolicyReasonInvalid), + Message: "failed getting ConfigMap default/example-configmap set as CACertificateRef: configmaps \"example-configmap\" not found", + }, + }, + { + name: "valid policy referencing not existing CACert (ConfigMap, group core)", + policy: &gatewayapi.BackendTLSPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-policy", + Namespace: "default", + }, + Spec: gatewayapi.BackendTLSPolicySpec{ + TargetRefs: []gatewayapi.LocalPolicyTargetReferenceWithSectionName{ + { + LocalPolicyTargetReference: gatewayapi.LocalPolicyTargetReference{ + Group: "core", + Kind: "Service", + Name: "example-service", + }, + }, + }, + Validation: gatewayapi.BackendTLSPolicyValidation{ + CACertificateRefs: []gatewayapi.LocalObjectReference{ + { + Group: "core", + Kind: "ConfigMap", + Name: gatewayapi.ObjectName("example-configmap"), + }, + }, + }, + }, + }, + expected: &metav1.Condition{ + Type: string(gatewayapi.PolicyConditionAccepted), + Status: metav1.ConditionFalse, + Reason: string(gatewayapi.PolicyReasonInvalid), + Message: "failed getting ConfigMap default/example-configmap set as CACertificateRef: configmaps \"example-configmap\" not found", + }, + }, } scheme := runtime.NewScheme() + require.NoError(t, clientgoscheme.AddToScheme(scheme)) require.NoError(t, gatewayapi.InstallV1(scheme)) require.NoError(t, gatewayapi.InstallV1alpha3(scheme)) @@ -784,6 +856,11 @@ func TestValidateBackendTLSPolicy(t *testing.T) { backendTLSPolicyTargetRefIndexKey, indexBackendTLSPolicyOnTargetRef, ). + WithIndex( + &gatewayapi.BackendTLSPolicy{}, + backendTLSPolicyValidationCARefIndexKey, + indexBackendTLSPolicyOnValidationCACertificateRef, + ). Build() r := &BackendTLSPolicyReconciler{