diff --git a/CHANGELOG.md b/CHANGELOG.md index d654e2dc1ae..5e75673ee21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,7 @@ Here is an overview of all new **experimental** features: ### Improvements - **General**: Add parameter queryParameters to prometheus-scaler ([#4962](https://github.com/kedacore/keda/issues/4962)) +- **General**: Support TriggerAuthentication properties from ConfigMap ([#4830](https://github.com/kedacore/keda/issues/4830)) - **General**: TODO ([#XXX](https://github.com/kedacore/keda/issues/XXX)) - **Hashicorp Vault**: Add support to get secret that needs write operation (e.g. pki) ([#5067](https://github.com/kedacore/keda/issues/5067)) - **Kafka Scaler**: Ability to set upper bound to the number of partitions with lag ([#3997](https://github.com/kedacore/keda/issues/3997)) diff --git a/apis/keda/v1alpha1/triggerauthentication_types.go b/apis/keda/v1alpha1/triggerauthentication_types.go index 578bc093f48..9483abedb6b 100644 --- a/apis/keda/v1alpha1/triggerauthentication_types.go +++ b/apis/keda/v1alpha1/triggerauthentication_types.go @@ -78,6 +78,9 @@ type TriggerAuthenticationSpec struct { // +optional SecretTargetRef []AuthSecretTargetRef `json:"secretTargetRef,omitempty"` + // +optional + ConfigMapTargetRef []AuthConfigMapTargetRef `json:"configMapTargetRef,omitempty"` + // +optional Env []AuthEnvironment `json:"env,omitempty"` @@ -142,8 +145,14 @@ func (a *AuthPodIdentity) GetIdentityID() string { return *a.IdentityID } +// AuthConfigMapTargetRef is used to authenticate using a reference to a config map +type AuthConfigMapTargetRef AuthTargetRef + // AuthSecretTargetRef is used to authenticate using a reference to a secret -type AuthSecretTargetRef struct { +type AuthSecretTargetRef AuthTargetRef + +// AuthTargetRef is used to authenticate using a reference to a resource +type AuthTargetRef struct { Parameter string `json:"parameter"` Name string `json:"name"` Key string `json:"key"` diff --git a/apis/keda/v1alpha1/zz_generated.deepcopy.go b/apis/keda/v1alpha1/zz_generated.deepcopy.go index 4b09d3a6f18..e0fdc9c51ee 100755 --- a/apis/keda/v1alpha1/zz_generated.deepcopy.go +++ b/apis/keda/v1alpha1/zz_generated.deepcopy.go @@ -47,6 +47,21 @@ func (in *AdvancedConfig) DeepCopy() *AdvancedConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuthConfigMapTargetRef) DeepCopyInto(out *AuthConfigMapTargetRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthConfigMapTargetRef. +func (in *AuthConfigMapTargetRef) DeepCopy() *AuthConfigMapTargetRef { + if in == nil { + return nil + } + out := new(AuthConfigMapTargetRef) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AuthEnvironment) DeepCopyInto(out *AuthEnvironment) { *out = *in @@ -97,6 +112,21 @@ func (in *AuthSecretTargetRef) DeepCopy() *AuthSecretTargetRef { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuthTargetRef) DeepCopyInto(out *AuthTargetRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthTargetRef. +func (in *AuthTargetRef) DeepCopy() *AuthTargetRef { + if in == nil { + return nil + } + out := new(AuthTargetRef) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AuthenticationRef) DeepCopyInto(out *AuthenticationRef) { *out = *in @@ -914,6 +944,11 @@ func (in *TriggerAuthenticationSpec) DeepCopyInto(out *TriggerAuthenticationSpec *out = make([]AuthSecretTargetRef, len(*in)) copy(*out, *in) } + if in.ConfigMapTargetRef != nil { + in, out := &in.ConfigMapTargetRef, &out.ConfigMapTargetRef + *out = make([]AuthConfigMapTargetRef, len(*in)) + copy(*out, *in) + } if in.Env != nil { in, out := &in.Env, &out.Env *out = make([]AuthEnvironment, len(*in)) diff --git a/config/crd/bases/keda.sh_clustertriggerauthentications.yaml b/config/crd/bases/keda.sh_clustertriggerauthentications.yaml index 17b46cc193c..cc9cacc688f 100644 --- a/config/crd/bases/keda.sh_clustertriggerauthentications.yaml +++ b/config/crd/bases/keda.sh_clustertriggerauthentications.yaml @@ -137,6 +137,23 @@ spec: - secrets - vaultUri type: object + configMapTargetRef: + items: + description: AuthConfigMapTargetRef is used to authenticate using + a reference to a config map + properties: + key: + type: string + name: + type: string + parameter: + type: string + required: + - key + - name + - parameter + type: object + type: array env: items: description: AuthEnvironment is used to authenticate using environment diff --git a/config/crd/bases/keda.sh_triggerauthentications.yaml b/config/crd/bases/keda.sh_triggerauthentications.yaml index ab861624479..6589a44301b 100644 --- a/config/crd/bases/keda.sh_triggerauthentications.yaml +++ b/config/crd/bases/keda.sh_triggerauthentications.yaml @@ -136,6 +136,23 @@ spec: - secrets - vaultUri type: object + configMapTargetRef: + items: + description: AuthConfigMapTargetRef is used to authenticate using + a reference to a config map + properties: + key: + type: string + name: + type: string + parameter: + type: string + required: + - key + - name + - parameter + type: object + type: array env: items: description: AuthEnvironment is used to authenticate using environment diff --git a/pkg/scaling/resolver/scale_resolvers.go b/pkg/scaling/resolver/scale_resolvers.go index f84011bbaaa..99eb4e9fb1f 100644 --- a/pkg/scaling/resolver/scale_resolvers.go +++ b/pkg/scaling/resolver/scale_resolvers.go @@ -244,6 +244,11 @@ func resolveAuthRef(ctx context.Context, client client.Client, logger logr.Logge } } } + if triggerAuthSpec.ConfigMapTargetRef != nil { + for _, e := range triggerAuthSpec.ConfigMapTargetRef { + result[e.Parameter] = resolveAuthConfigMap(ctx, client, logger, e.Name, triggerNamespace, e.Key) + } + } if triggerAuthSpec.SecretTargetRef != nil { for _, e := range triggerAuthSpec.SecretTargetRef { result[e.Parameter] = resolveAuthSecret(ctx, client, logger, e.Name, triggerNamespace, e.Key, secretsLister) @@ -503,6 +508,16 @@ func resolveConfigValue(ctx context.Context, client client.Client, configKeyRef return configMap.Data[keyName], nil } +func resolveAuthConfigMap(ctx context.Context, client client.Client, logger logr.Logger, name, namespace, key string) string { + ref := &corev1.ConfigMapKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: name}, Key: key} + val, err := resolveConfigValue(ctx, client, ref, key, namespace) + if err != nil { + logger.Error(err, "error trying to get config map from namespace", "ConfigMap.Namespace", namespace, "ConfigMap.Name", name) + return "" + } + return val +} + func resolveAuthSecret(ctx context.Context, client client.Client, logger logr.Logger, name, namespace, key string, secretsLister corev1listers.SecretLister) string { if name == "" || namespace == "" || key == "" { logger.Error(fmt.Errorf("error trying to get secret"), "name, namespace and key are required", "Secret.Namespace", namespace, "Secret.Name", name, "key", key) diff --git a/pkg/scaling/resolver/scale_resolvers_test.go b/pkg/scaling/resolver/scale_resolvers_test.go index 7db11297362..32596824b46 100644 --- a/pkg/scaling/resolver/scale_resolvers_test.go +++ b/pkg/scaling/resolver/scale_resolvers_test.go @@ -42,6 +42,9 @@ var ( secretName = "supersecret" secretKey = "mysecretkey" secretData = "secretDataHere" + cmName = "supercm" + cmKey = "mycmkey" + cmData = "cmDataHere" trueValue = true falseValue = false envKey = "test-env-key" @@ -320,6 +323,86 @@ func TestResolveAuthRef(t *testing.T) { expected: map[string]string{"host": secretData}, expectedPodIdentity: kedav1alpha1.AuthPodIdentity{Provider: kedav1alpha1.PodIdentityProviderNone}, }, + { + name: "triggerauth exists and config map", + existing: []runtime.Object{ + &kedav1alpha1.TriggerAuthentication{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: triggerAuthenticationName, + }, + Spec: kedav1alpha1.TriggerAuthenticationSpec{ + PodIdentity: &kedav1alpha1.AuthPodIdentity{ + Provider: kedav1alpha1.PodIdentityProviderNone, + }, + ConfigMapTargetRef: []kedav1alpha1.AuthConfigMapTargetRef{ + { + Parameter: "host", + Name: cmName, + Key: cmKey, + }, + }, + }, + }, + &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: cmName, + }, + Data: map[string]string{cmKey: cmData}, + }, + }, + soar: &kedav1alpha1.AuthenticationRef{Name: triggerAuthenticationName}, + expected: map[string]string{"host": cmData}, + expectedPodIdentity: kedav1alpha1.AuthPodIdentity{Provider: kedav1alpha1.PodIdentityProviderNone}, + }, + { + name: "triggerauth exists secret + config map", + existing: []runtime.Object{ + &kedav1alpha1.TriggerAuthentication{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: triggerAuthenticationName, + }, + Spec: kedav1alpha1.TriggerAuthenticationSpec{ + PodIdentity: &kedav1alpha1.AuthPodIdentity{ + Provider: kedav1alpha1.PodIdentityProviderNone, + }, + SecretTargetRef: []kedav1alpha1.AuthSecretTargetRef{ + { + Parameter: "host-secret", + Name: secretName, + Key: secretKey, + }, + }, + ConfigMapTargetRef: []kedav1alpha1.AuthConfigMapTargetRef{ + { + Parameter: "host-configmap", + Name: cmName, + Key: cmKey, + }, + }, + }, + }, + &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: cmName, + }, + Data: map[string]string{cmKey: cmData}, + }, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: secretName, + }, + Data: map[string][]byte{secretKey: []byte(secretData)}, + }, + }, + soar: &kedav1alpha1.AuthenticationRef{Name: triggerAuthenticationName}, + expected: map[string]string{"host-secret": secretData, "host-configmap": cmData}, + expectedPodIdentity: kedav1alpha1.AuthPodIdentity{Provider: kedav1alpha1.PodIdentityProviderNone}, + }, { name: "clustertriggerauth exists, podidentity nil", existing: []runtime.Object{ @@ -372,6 +455,45 @@ func TestResolveAuthRef(t *testing.T) { expected: map[string]string{"host": secretData}, expectedPodIdentity: kedav1alpha1.AuthPodIdentity{Provider: kedav1alpha1.PodIdentityProviderNone}, }, + { + name: "clustertriggerauth exists and secret + config map", + existing: []runtime.Object{ + &kedav1alpha1.ClusterTriggerAuthentication{ + ObjectMeta: metav1.ObjectMeta{ + Name: triggerAuthenticationName, + }, + Spec: kedav1alpha1.TriggerAuthenticationSpec{ + PodIdentity: &kedav1alpha1.AuthPodIdentity{ + Provider: kedav1alpha1.PodIdentityProviderNone, + }, + SecretTargetRef: []kedav1alpha1.AuthSecretTargetRef{ + { + Parameter: "host", + Name: secretName, + Key: secretKey, + }, + }, + }, + }, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: clusterNamespace, + Name: secretName, + }, + Data: map[string][]byte{secretKey: []byte(secretData)}, + }, + &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: clusterNamespace, + Name: secretName, + }, + Data: map[string]string{secretKey: secretData}, + }, + }, + soar: &kedav1alpha1.AuthenticationRef{Name: triggerAuthenticationName, Kind: "ClusterTriggerAuthentication"}, + expected: map[string]string{"host": secretData}, + expectedPodIdentity: kedav1alpha1.AuthPodIdentity{Provider: kedav1alpha1.PodIdentityProviderNone}, + }, { name: "clustertriggerauth exists and secret in the wrong namespace", existing: []runtime.Object{