Browse Source

chore: refactor/centralise secretKeyRef usage (#3022)

* chore: refactor/centralise secretKeyRef usage

Signed-off-by: Moritz Johner <beller.moritz@googlemail.com>
Moritz Johner 2 years ago
parent
commit
26f9c3f1f4
43 changed files with 600 additions and 850 deletions
  1. 2 2
      apis/externalsecrets/v1beta1/secretstore_conjur_types.go
  2. 7 7
      apis/externalsecrets/v1beta1/zz_generated.deepcopy.go
  3. 3 3
      docs/api/spec.md
  4. 3 2
      pkg/generator/gcr/gcr.go
  5. 1 1
      pkg/generator/gcr/gcr_test.go
  6. 12 9
      pkg/provider/akeyless/akeyless.go
  7. 4 28
      pkg/provider/akeyless/akeyless_api.go
  8. 30 56
      pkg/provider/akeyless/auth.go
  9. 12 53
      pkg/provider/alibaba/kms.go
  10. 14 50
      pkg/provider/aws/auth/auth.go
  11. 1 1
      pkg/provider/aws/auth/auth_test.go
  12. 12 30
      pkg/provider/azure/keyvault/keyvault.go
  13. 2 2
      pkg/provider/azure/keyvault/keyvault_auth_test.go
  14. 7 1
      pkg/provider/conjur/auth_jwt.go
  15. 28 38
      pkg/provider/conjur/provider.go
  16. 2 2
      pkg/provider/conjur/provider_test.go
  17. 10 27
      pkg/provider/delinea/provider.go
  18. 1 2
      pkg/provider/delinea/provider_test.go
  19. 9 30
      pkg/provider/doppler/client.go
  20. 13 21
      pkg/provider/gcp/secretmanager/auth.go
  21. 0 1
      pkg/provider/gcp/secretmanager/client.go
  22. 1 1
      pkg/provider/gcp/secretmanager/provider.go
  23. 8 30
      pkg/provider/gitlab/gitlab.go
  24. 2 2
      pkg/provider/gitlab/gitlab_test.go
  25. 1 1
      pkg/provider/gitlab/provider.go
  26. 11 35
      pkg/provider/ibm/provider.go
  27. 9 33
      pkg/provider/keepersecurity/provider.go
  28. 11 23
      pkg/provider/kubernetes/auth.go
  29. 10 21
      pkg/provider/onepassword/onepassword.go
  30. 22 33
      pkg/provider/oracle/oracle.go
  31. 1 1
      pkg/provider/oracle/oracle_test.go
  32. 11 36
      pkg/provider/scaleway/provider.go
  33. 9 2
      pkg/provider/senhasegura/auth/iso.go
  34. 0 57
      pkg/provider/senhasegura/auth/kubernetes_secret.go
  35. 27 55
      pkg/provider/vault/iamauth/iamauth.go
  36. 68 74
      pkg/provider/vault/vault.go
  37. 1 1
      pkg/provider/vault/vault_test.go
  38. 12 30
      pkg/provider/webhook/webhook.go
  39. 2 2
      pkg/provider/yandex/certificatemanager/certificatemanager_test.go
  40. 19 45
      pkg/provider/yandex/common/provider.go
  41. 2 2
      pkg/provider/yandex/lockbox/lockbox_test.go
  42. 71 0
      pkg/utils/resolvers/secret_ref.go
  43. 129 0
      pkg/utils/resolvers/secret_ref_test.go

+ 2 - 2
apis/externalsecrets/v1beta1/secretstore_conjur_types.go

@@ -27,12 +27,12 @@ type ConjurProvider struct {
 
 type ConjurAuth struct {
 	// +optional
-	Apikey *ConjurApikey `json:"apikey,omitempty"`
+	APIKey *ConjurAPIKey `json:"apikey,omitempty"`
 	// +optional
 	Jwt *ConjurJWT `json:"jwt,omitempty"`
 }
 
-type ConjurApikey struct {
+type ConjurAPIKey struct {
 	Account   string                    `json:"account"`
 	UserRef   *esmeta.SecretKeySelector `json:"userRef"`
 	APIKeyRef *esmeta.SecretKeySelector `json:"apiKeyRef"`

+ 7 - 7
apis/externalsecrets/v1beta1/zz_generated.deepcopy.go

@@ -654,7 +654,7 @@ func (in *ClusterSecretStoreList) DeepCopyObject() runtime.Object {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ConjurApikey) DeepCopyInto(out *ConjurApikey) {
+func (in *ConjurAPIKey) DeepCopyInto(out *ConjurAPIKey) {
 	*out = *in
 	if in.UserRef != nil {
 		in, out := &in.UserRef, &out.UserRef
@@ -668,12 +668,12 @@ func (in *ConjurApikey) DeepCopyInto(out *ConjurApikey) {
 	}
 }
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConjurApikey.
-func (in *ConjurApikey) DeepCopy() *ConjurApikey {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConjurAPIKey.
+func (in *ConjurAPIKey) DeepCopy() *ConjurAPIKey {
 	if in == nil {
 		return nil
 	}
-	out := new(ConjurApikey)
+	out := new(ConjurAPIKey)
 	in.DeepCopyInto(out)
 	return out
 }
@@ -681,9 +681,9 @@ func (in *ConjurApikey) DeepCopy() *ConjurApikey {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *ConjurAuth) DeepCopyInto(out *ConjurAuth) {
 	*out = *in
-	if in.Apikey != nil {
-		in, out := &in.Apikey, &out.Apikey
-		*out = new(ConjurApikey)
+	if in.APIKey != nil {
+		in, out := &in.APIKey, &out.APIKey
+		*out = new(ConjurAPIKey)
 		(*in).DeepCopyInto(*out)
 	}
 	if in.Jwt != nil {

+ 3 - 3
docs/api/spec.md

@@ -1691,7 +1691,7 @@ Kubernetes meta/v1.LabelSelector
 </tr>
 </tbody>
 </table>
-<h3 id="external-secrets.io/v1beta1.ConjurApikey">ConjurApikey
+<h3 id="external-secrets.io/v1beta1.ConjurAPIKey">ConjurAPIKey
 </h3>
 <p>
 (<em>Appears on:</em>
@@ -1763,8 +1763,8 @@ External Secrets meta/v1.SecretKeySelector
 <td>
 <code>apikey</code></br>
 <em>
-<a href="#external-secrets.io/v1beta1.ConjurApikey">
-ConjurApikey
+<a href="#external-secrets.io/v1beta1.ConjurAPIKey">
+ConjurAPIKey
 </a>
 </em>
 </td>

+ 3 - 2
pkg/generator/gcr/gcr.go

@@ -27,6 +27,7 @@ import (
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	genv1alpha1 "github.com/external-secrets/external-secrets/apis/generators/v1alpha1"
 	"github.com/external-secrets/external-secrets/pkg/provider/gcp/secretmanager"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 type Generator struct{}
@@ -65,7 +66,7 @@ func (g *Generator) generate(
 	ts, err := tokenSource(ctx, esv1beta1.GCPSMAuth{
 		SecretRef:        (*esv1beta1.GCPSMAuthSecretRef)(res.Spec.Auth.SecretRef),
 		WorkloadIdentity: (*esv1beta1.GCPWorkloadIdentity)(res.Spec.Auth.WorkloadIdentity),
-	}, res.Spec.ProjectID, false, kube, namespace)
+	}, res.Spec.ProjectID, resolvers.EmptyStoreKind, kube, namespace)
 	if err != nil {
 		return nil, err
 	}
@@ -81,7 +82,7 @@ func (g *Generator) generate(
 	}, nil
 }
 
-type tokenSourceFunc func(ctx context.Context, auth esv1beta1.GCPSMAuth, projectID string, isClusterKind bool, kube client.Client, namespace string) (oauth2.TokenSource, error)
+type tokenSourceFunc func(ctx context.Context, auth esv1beta1.GCPSMAuth, projectID string, storeKind string, kube client.Client, namespace string) (oauth2.TokenSource, error)
 
 func parseSpec(data []byte) (*genv1alpha1.GCRAccessToken, error) {
 	var spec genv1alpha1.GCRAccessToken

+ 1 - 1
pkg/generator/gcr/gcr_test.go

@@ -65,7 +65,7 @@ func TestGenerate(t *testing.T) {
 						"foo": []byte("bar"),
 					},
 				}).Build(),
-				fakeTokenSource: func(ctx context.Context, auth v1beta1.GCPSMAuth, projectID string, isClusterKind bool, kube client.Client, namespace string) (oauth2.TokenSource, error) {
+				fakeTokenSource: func(ctx context.Context, auth v1beta1.GCPSMAuth, projectID string, storeKind string, kube client.Client, namespace string) (oauth2.TokenSource, error) {
 					return oauth2.StaticTokenSource(&oauth2.Token{
 						AccessToken: "1234",
 						Expiry:      time.Unix(5555, 0),

+ 12 - 9
pkg/provider/akeyless/akeyless.go

@@ -39,6 +39,7 @@ import (
 	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
 	"github.com/external-secrets/external-secrets/pkg/find"
 	"github.com/external-secrets/external-secrets/pkg/utils"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 const (
@@ -426,12 +427,14 @@ func (a *akeylessBase) getCACertPool(provider *esv1beta1.AkeylessProvider) (*x50
 		}
 		ok := caCertPool.AppendCertsFromPEM(pem)
 		if !ok {
-			return nil, fmt.Errorf("failed to append cabundle")
+			return nil, fmt.Errorf("failed to append caBundle")
 		}
 	}
 
-	if provider.CAProvider != nil && a.storeKind == esv1beta1.ClusterSecretStoreKind && provider.CAProvider.Namespace == nil {
-		return nil, fmt.Errorf("missing namespace on CAProvider secret")
+	if provider.CAProvider != nil &&
+		a.storeKind == esv1beta1.ClusterSecretStoreKind &&
+		provider.CAProvider.Namespace == nil {
+		return nil, fmt.Errorf("missing namespace on caProvider secret")
 	}
 
 	if provider.CAProvider != nil {
@@ -444,7 +447,7 @@ func (a *akeylessBase) getCACertPool(provider *esv1beta1.AkeylessProvider) (*x50
 		case esv1beta1.CAProviderTypeConfigMap:
 			cert, err = a.getCertFromConfigMap(provider)
 		default:
-			err = fmt.Errorf("unknown caprovider type: %s", provider.CAProvider.Type)
+			err = fmt.Errorf("unknown CAProvider type: %s", provider.CAProvider.Type)
 		}
 
 		if err != nil {
@@ -456,7 +459,7 @@ func (a *akeylessBase) getCACertPool(provider *esv1beta1.AkeylessProvider) (*x50
 		}
 		ok := caCertPool.AppendCertsFromPEM(pem)
 		if !ok {
-			return nil, fmt.Errorf("failed to append cabundle")
+			return nil, fmt.Errorf("failed to append caBundle")
 		}
 	}
 	return caCertPool, nil
@@ -473,12 +476,12 @@ func (a *akeylessBase) getCertFromSecret(provider *esv1beta1.AkeylessProvider) (
 	}
 
 	ctx := context.Background()
-	res, err := a.secretKeyRef(ctx, &secretRef)
+	cert, err := resolvers.SecretKeyRef(ctx, a.kube, a.storeKind, a.namespace, &secretRef)
 	if err != nil {
 		return nil, err
 	}
 
-	return []byte(res), nil
+	return []byte(cert), nil
 }
 
 func (a *akeylessBase) getCertFromConfigMap(provider *esv1beta1.AkeylessProvider) ([]byte, error) {
@@ -494,12 +497,12 @@ func (a *akeylessBase) getCertFromConfigMap(provider *esv1beta1.AkeylessProvider
 	ctx := context.Background()
 	err := a.kube.Get(ctx, objKey, configMapRef)
 	if err != nil {
-		return nil, fmt.Errorf("failed to get caprovider secret %s: %w", objKey.Name, err)
+		return nil, fmt.Errorf("failed to get caProvider secret %s: %w", objKey.Name, err)
 	}
 
 	val, ok := configMapRef.Data[provider.CAProvider.Key]
 	if !ok {
-		return nil, fmt.Errorf("failed to get caprovider configmap %s -> %s", objKey.Name, provider.CAProvider.Key)
+		return nil, fmt.Errorf("failed to get caProvider configMap %s -> %s", objKey.Name, provider.CAProvider.Key)
 	}
 
 	return []byte(val), nil

+ 4 - 28
pkg/provider/akeyless/akeyless_api.go

@@ -35,6 +35,7 @@ import (
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 var apiErr akeyless.GenericOpenAPIError
@@ -335,7 +336,7 @@ func (a *akeylessBase) getK8SServiceAccountJWT(ctx context.Context, kubernetesAu
 				tokenRef = kubernetesAuth.SecretRef.DeepCopy()
 				tokenRef.Key = "token"
 			}
-			jwt, err := a.secretKeyRef(ctx, tokenRef)
+			jwt, err := resolvers.SecretKeyRef(ctx, a.kube, a.storeKind, a.namespace, tokenRef)
 			if err != nil {
 				return "", err
 			}
@@ -363,7 +364,7 @@ func (a *akeylessBase) getJWTFromServiceAccount(ctx context.Context, serviceAcco
 		return "", fmt.Errorf(errGetKubeSASecrets, ref.Name)
 	}
 	for _, tokenRef := range serviceAccount.Secrets {
-		retval, err := a.secretKeyRef(ctx, &esmeta.SecretKeySelector{
+		token, err := resolvers.SecretKeyRef(ctx, a.kube, a.storeKind, a.namespace, &esmeta.SecretKeySelector{
 			Name:      tokenRef.Name,
 			Namespace: &ref.Namespace,
 			Key:       "token",
@@ -372,36 +373,11 @@ func (a *akeylessBase) getJWTFromServiceAccount(ctx context.Context, serviceAcco
 			continue
 		}
 
-		return retval, nil
+		return token, nil
 	}
 	return "", fmt.Errorf(errGetKubeSANoToken, ref.Name)
 }
 
-func (a *akeylessBase) secretKeyRef(ctx context.Context, secretRef *esmeta.SecretKeySelector) (string, error) {
-	secret := &corev1.Secret{}
-	ref := types.NamespacedName{
-		Namespace: a.namespace,
-		Name:      secretRef.Name,
-	}
-	if (a.storeKind == esv1beta1.ClusterSecretStoreKind) &&
-		(secretRef.Namespace != nil) {
-		ref.Namespace = *secretRef.Namespace
-	}
-	err := a.kube.Get(ctx, ref, secret)
-	if err != nil {
-		return "", fmt.Errorf(errGetKubeSecret, ref.Name, err)
-	}
-
-	keyBytes, ok := secret.Data[secretRef.Key]
-	if !ok {
-		return "", fmt.Errorf(errSecretKeyFmt, secretRef.Key)
-	}
-
-	value := string(keyBytes)
-	valueStr := strings.TrimSpace(value)
-	return valueStr, nil
-}
-
 func (a *akeylessBase) getJWTfromServiceAccountToken(ctx context.Context, serviceAccountRef esmeta.ServiceAccountSelector, additionalAud []string, expirationSeconds int64) (string, error) {
 	audiences := serviceAccountRef.Audiences
 	if len(additionalAud) > 0 {

+ 30 - 56
pkg/provider/akeyless/auth.go

@@ -18,19 +18,15 @@ import (
 	"context"
 	"fmt"
 
-	v1 "k8s.io/api/core/v1"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-
-	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 const (
-	errInvalidClusterStoreMissingAKIDNamespace = "invalid ClusterSecretStore: missing Akeyless AccessID Namespace"
-	errInvalidClusterStoreMissingSAKNamespace  = "invalid ClusterSecretStore: missing Akeyless AccessType Namespace"
-	errFetchAKIDSecret                         = "could not fetch accessID secret: %w"
-	errFetchSAKSecret                          = "could not fetch AccessType secret: %w"
-	errMissingSAK                              = "missing SecretAccessKey"
-	errMissingAKID                             = "missing AccessKeyID"
+	errFetchAccessIDSecret        = "could not fetch accessID secret: %w"
+	errFetchAccessTypeSecret      = "could not fetch AccessType secret: %w"
+	errFetchAccessTypeParamSecret = "could not fetch AccessTypeParam secret: %w"
+	errMissingSAK                 = "missing SecretAccessKey"
+	errMissingAKID                = "missing AccessKeyID"
 )
 
 func (a *akeylessBase) TokenFromSecretRef(ctx context.Context) (string, error) {
@@ -44,58 +40,36 @@ func (a *akeylessBase) TokenFromSecretRef(ctx context.Context) (string, error) {
 		return a.GetToken(auth.AccessID, "k8s", auth.K8sConfName, auth)
 	}
 
-	ke := client.ObjectKey{
-		Name:      prov.Auth.SecretRef.AccessID.Name,
-		Namespace: a.namespace, // default to ExternalSecret namespace
-	}
-	// only ClusterStore is allowed to set namespace (and then it's required)
-	if a.store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind {
-		if prov.Auth.SecretRef.AccessID.Namespace == nil {
-			return "", fmt.Errorf(errInvalidClusterStoreMissingAKIDNamespace)
-		}
-		ke.Namespace = *prov.Auth.SecretRef.AccessID.Namespace
-	}
-	accessIDSecret := v1.Secret{}
-	err = a.kube.Get(ctx, ke, &accessIDSecret)
+	accessID, err := resolvers.SecretKeyRef(
+		ctx,
+		a.kube,
+		a.storeKind,
+		a.namespace,
+		&prov.Auth.SecretRef.AccessID,
+	)
 	if err != nil {
-		return "", fmt.Errorf(errFetchAKIDSecret, err)
-	}
-	ke = client.ObjectKey{
-		Name:      prov.Auth.SecretRef.AccessType.Name,
-		Namespace: a.namespace, // default to ExternalSecret namespace
+		return "", fmt.Errorf(errFetchAccessIDSecret, err)
 	}
-	// only ClusterStore is allowed to set namespace (and then it's required)
-	if a.store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind {
-		if prov.Auth.SecretRef.AccessType.Namespace == nil {
-			return "", fmt.Errorf(errInvalidClusterStoreMissingSAKNamespace)
-		}
-		ke.Namespace = *prov.Auth.SecretRef.AccessType.Namespace
-	}
-	accessTypeSecret := v1.Secret{}
-	err = a.kube.Get(ctx, ke, &accessTypeSecret)
+	accessType, err := resolvers.SecretKeyRef(
+		ctx,
+		a.kube,
+		a.storeKind,
+		a.namespace,
+		&prov.Auth.SecretRef.AccessType,
+	)
 	if err != nil {
-		return "", fmt.Errorf(errFetchSAKSecret, err)
-	}
-
-	ke = client.ObjectKey{
-		Name:      prov.Auth.SecretRef.AccessTypeParam.Name,
-		Namespace: a.namespace, // default to ExternalSecret namespace
-	}
-	// only ClusterStore is allowed to set namespace (and then it's required)
-	if a.store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind {
-		if prov.Auth.SecretRef.AccessType.Namespace == nil {
-			return "", fmt.Errorf(errInvalidClusterStoreMissingSAKNamespace)
-		}
-		ke.Namespace = *prov.Auth.SecretRef.AccessType.Namespace
+		return "", fmt.Errorf(errFetchAccessTypeSecret, err)
 	}
-	accessTypeParamSecret := v1.Secret{}
-	err = a.kube.Get(ctx, ke, &accessTypeParamSecret)
+	accessTypeParam, err := resolvers.SecretKeyRef(
+		ctx,
+		a.kube,
+		a.storeKind,
+		a.namespace,
+		&prov.Auth.SecretRef.AccessTypeParam,
+	)
 	if err != nil {
-		return "", fmt.Errorf(errFetchSAKSecret, err)
+		return "", fmt.Errorf(errFetchAccessTypeParamSecret, err)
 	}
-	accessID := string(accessIDSecret.Data[prov.Auth.SecretRef.AccessID.Key])
-	accessType := string(accessTypeSecret.Data[prov.Auth.SecretRef.AccessType.Key])
-	accessTypeParam := string(accessTypeSecret.Data[prov.Auth.SecretRef.AccessTypeParam.Key])
 
 	if accessID == "" {
 		return "", fmt.Errorf(errMissingSAK)

+ 12 - 53
pkg/provider/alibaba/kms.go

@@ -26,22 +26,18 @@ import (
 	"github.com/avast/retry-go/v4"
 	"github.com/tidwall/gjson"
 	corev1 "k8s.io/api/core/v1"
-	"k8s.io/apimachinery/pkg/types"
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	"github.com/external-secrets/external-secrets/pkg/utils"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 const (
-	errAlibabaClient                           = "cannot setup new Alibaba client: %w"
-	errAlibabaCredSecretName                   = "invalid Alibaba SecretStore resource: missing Alibaba APIKey"
-	errUninitalizedAlibabaProvider             = "provider Alibaba is not initialized"
-	errInvalidClusterStoreMissingAKIDNamespace = "invalid ClusterStore, missing  AccessKeyID namespace"
-	errInvalidClusterStoreMissingSKNamespace   = "invalid ClusterStore, missing namespace"
-	errFetchAKIDSecret                         = "could not fetch AccessKeyID secret: %w"
-	errMissingSAK                              = "missing AccessSecretKey"
-	errMissingAKID                             = "missing AccessKeyID"
+	errAlibabaClient               = "cannot setup new Alibaba client: %w"
+	errUninitalizedAlibabaProvider = "provider Alibaba is not initialized"
+	errFetchAccessKeyID            = "could not fetch AccessKeyID secret: %w"
+	errFetchAccessKeySecret        = "could not fetch AccessKeySecret secret: %w"
 )
 
 // https://github.com/external-secrets/external-secrets/issues/644
@@ -222,54 +218,17 @@ func newAccessKeyAuth(ctx context.Context, kube kclient.Client, store esv1beta1.
 	storeSpec := store.GetSpec()
 	alibabaSpec := storeSpec.Provider.Alibaba
 	storeKind := store.GetObjectKind().GroupVersionKind().Kind
-
-	credentialsSecret := &corev1.Secret{}
-	credentialsSecretName := alibabaSpec.Auth.SecretRef.AccessKeyID.Name
-	if credentialsSecretName == "" {
-		return nil, fmt.Errorf(errAlibabaCredSecretName)
-	}
-	objectKey := types.NamespacedName{
-		Name:      credentialsSecretName,
-		Namespace: namespace,
-	}
-
-	// only ClusterStore is allowed to set namespace (and then it's required)
-	if storeKind == esv1beta1.ClusterSecretStoreKind {
-		if alibabaSpec.Auth.SecretRef.AccessKeyID.Namespace == nil {
-			return nil, fmt.Errorf(errInvalidClusterStoreMissingAKIDNamespace)
-		}
-		objectKey.Namespace = *alibabaSpec.Auth.SecretRef.AccessKeyID.Namespace
-	}
-
-	err := kube.Get(ctx, objectKey, credentialsSecret)
+	accessKeyID, err := resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, &alibabaSpec.Auth.SecretRef.AccessKeyID)
 	if err != nil {
-		return nil, fmt.Errorf(errFetchAKIDSecret, err)
-	}
-
-	objectKey = types.NamespacedName{
-		Name:      alibabaSpec.Auth.SecretRef.AccessKeySecret.Name,
-		Namespace: namespace,
-	}
-	if storeKind == esv1beta1.ClusterSecretStoreKind {
-		if alibabaSpec.Auth.SecretRef.AccessKeySecret.Namespace == nil {
-			return nil, fmt.Errorf(errInvalidClusterStoreMissingSKNamespace)
-		}
-		objectKey.Namespace = *alibabaSpec.Auth.SecretRef.AccessKeySecret.Namespace
-	}
-
-	accessKeyID := credentialsSecret.Data[alibabaSpec.Auth.SecretRef.AccessKeyID.Key]
-	if (accessKeyID == nil) || (len(accessKeyID) == 0) {
-		return nil, fmt.Errorf(errMissingAKID)
+		return nil, fmt.Errorf(errFetchAccessKeyID, err)
 	}
-
-	accessKeySecret := credentialsSecret.Data[alibabaSpec.Auth.SecretRef.AccessKeySecret.Key]
-	if (accessKeySecret == nil) || (len(accessKeySecret) == 0) {
-		return nil, fmt.Errorf(errMissingSAK)
+	accessKeySecret, err := resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, &alibabaSpec.Auth.SecretRef.AccessKeySecret)
+	if err != nil {
+		return nil, fmt.Errorf(errFetchAccessKeySecret, err)
 	}
-
 	credentialConfig := &credential.Config{
-		AccessKeyId:     utils.Ptr(string(accessKeyID)),
-		AccessKeySecret: utils.Ptr(string(accessKeySecret)),
+		AccessKeyId:     utils.Ptr(accessKeyID),
+		AccessKeySecret: utils.Ptr(accessKeySecret),
 		Type:            utils.Ptr("access_key"),
 		ConnectTimeout:  utils.Ptr(30),
 		Timeout:         utils.Ptr(60),

+ 14 - 50
pkg/provider/aws/auth/auth.go

@@ -38,6 +38,7 @@ import (
 	"github.com/external-secrets/external-secrets/pkg/cache"
 	"github.com/external-secrets/external-secrets/pkg/feature"
 	"github.com/external-secrets/external-secrets/pkg/provider/aws/util"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 // Config contains configuration to create a new AWS provider.
@@ -58,13 +59,9 @@ const (
 	audienceAnnotation   = "eks.amazonaws.com/audience"
 	defaultTokenAudience = "sts.amazonaws.com"
 
-	errInvalidClusterStoreMissingAKIDNamespace = "invalid ClusterSecretStore: missing AWS AccessKeyID Namespace"
-	errInvalidClusterStoreMissingSAKNamespace  = "invalid ClusterSecretStore: missing AWS SecretAccessKey Namespace"
-	errFetchAKIDSecret                         = "could not fetch accessKeyID secret: %w"
-	errFetchSAKSecret                          = "could not fetch SecretAccessKey secret: %w"
-	errFetchSTSecret                           = "could not fetch SessionToken secret: %w"
-	errMissingSAK                              = "missing SecretAccessKey"
-	errMissingAKID                             = "missing AccessKeyID"
+	errFetchAKIDSecret = "could not fetch accessKeyID secret: %w"
+	errFetchSAKSecret  = "could not fetch SecretAccessKey secret: %w"
+	errFetchSTSecret   = "could not fetch SessionToken secret: %w"
 )
 
 func init() {
@@ -98,11 +95,11 @@ func New(ctx context.Context, store esv1beta1.GenericStore, kube client.Client,
 		}
 	}
 
-	// use credentials from sercretRef
+	// use credentials from secretRef
 	secretRef := prov.Auth.SecretRef
 	if secretRef != nil {
 		log.V(1).Info("using credentials from secretRef")
-		creds, err = credsFromSecretRef(ctx, prov.Auth, isClusterKind, kube, namespace)
+		creds, err = credsFromSecretRef(ctx, prov.Auth, store.GetKind(), kube, namespace)
 		if err != nil {
 			return nil, err
 		}
@@ -176,11 +173,11 @@ func NewGeneratorSession(ctx context.Context, auth esv1beta1.AWSAuth, role, regi
 		}
 	}
 
-	// use credentials from sercretRef
+	// use credentials from secretRef
 	secretRef := auth.SecretRef
 	if secretRef != nil {
 		log.V(1).Info("using credentials from secretRef")
-		creds, err = credsFromSecretRef(ctx, auth, false, kube, namespace)
+		creds, err = credsFromSecretRef(ctx, auth, "", kube, namespace)
 		if err != nil {
 			return nil, err
 		}
@@ -211,55 +208,22 @@ func NewGeneratorSession(ctx context.Context, auth esv1beta1.AWSAuth, role, regi
 // construct a aws.Credentials object
 // The namespace of the external secret is used if the ClusterSecretStore does not specify a namespace (referentAuth)
 // If the ClusterSecretStore defines a namespace it will take precedence.
-func credsFromSecretRef(ctx context.Context, auth esv1beta1.AWSAuth, isClusterKind bool, kube client.Client, namespace string) (*credentials.Credentials, error) {
-	ke := client.ObjectKey{
-		Name:      auth.SecretRef.AccessKeyID.Name,
-		Namespace: namespace,
-	}
-	if isClusterKind && auth.SecretRef.AccessKeyID.Namespace != nil {
-		ke.Namespace = *auth.SecretRef.AccessKeyID.Namespace
-	}
-	akSecret := v1.Secret{}
-	err := kube.Get(ctx, ke, &akSecret)
-	if err != nil {
-		return nil, fmt.Errorf(errFetchAKIDSecret, err)
-	}
-	ke = client.ObjectKey{
-		Name:      auth.SecretRef.SecretAccessKey.Name,
-		Namespace: namespace,
-	}
-	if isClusterKind && auth.SecretRef.SecretAccessKey.Namespace != nil {
-		ke.Namespace = *auth.SecretRef.SecretAccessKey.Namespace
-	}
-	sakSecret := v1.Secret{}
-	err = kube.Get(ctx, ke, &sakSecret)
+func credsFromSecretRef(ctx context.Context, auth esv1beta1.AWSAuth, storeKind string, kube client.Client, namespace string) (*credentials.Credentials, error) {
+	sak, err := resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, &auth.SecretRef.SecretAccessKey)
 	if err != nil {
 		return nil, fmt.Errorf(errFetchSAKSecret, err)
 	}
-	sak := string(sakSecret.Data[auth.SecretRef.SecretAccessKey.Key])
-	aks := string(akSecret.Data[auth.SecretRef.AccessKeyID.Key])
-	if sak == "" {
-		return nil, fmt.Errorf(errMissingSAK)
-	}
-	if aks == "" {
-		return nil, fmt.Errorf(errMissingAKID)
+	aks, err := resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, &auth.SecretRef.AccessKeyID)
+	if err != nil {
+		return nil, fmt.Errorf(errFetchAKIDSecret, err)
 	}
 
 	var sessionToken string
 	if auth.SecretRef.SessionToken != nil {
-		ke = client.ObjectKey{
-			Name:      auth.SecretRef.SessionToken.Name,
-			Namespace: namespace,
-		}
-		if isClusterKind && auth.SecretRef.SessionToken.Namespace != nil {
-			ke.Namespace = *auth.SecretRef.SessionToken.Namespace
-		}
-		stSecret := v1.Secret{}
-		err = kube.Get(ctx, ke, &stSecret)
+		sessionToken, err = resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, auth.SecretRef.SessionToken)
 		if err != nil {
 			return nil, fmt.Errorf(errFetchSTSecret, err)
 		}
-		sessionToken = string(stSecret.Data[auth.SecretRef.SessionToken.Key])
 	}
 
 	return credentials.NewStaticCredentials(aks, sak, sessionToken), err

+ 1 - 1
pkg/provider/aws/auth/auth_test.go

@@ -224,7 +224,7 @@ func TestNewSession(t *testing.T) {
 					Data: map[string][]byte{},
 				},
 			},
-			expectErr: "missing SecretAccessKey",
+			expectErr: "could not fetch SecretAccessKey secret: cannot find secret data for key: \"two\"",
 		},
 		{
 			name:      "should not be able to access secrets from different namespace",

+ 12 - 30
pkg/provider/azure/keyvault/keyvault.go

@@ -48,10 +48,10 @@ import (
 	ctrlcfg "sigs.k8s.io/controller-runtime/pkg/client/config"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
-	smmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
 	"github.com/external-secrets/external-secrets/pkg/constants"
 	"github.com/external-secrets/external-secrets/pkg/metrics"
 	"github.com/external-secrets/external-secrets/pkg/utils"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 const (
@@ -886,46 +886,28 @@ func (a *Azure) authorizerForServicePrincipal(ctx context.Context) (autorest.Aut
 	if a.provider.AuthSecretRef.ClientID == nil || a.provider.AuthSecretRef.ClientSecret == nil {
 		return nil, fmt.Errorf(errMissingClientIDSecret)
 	}
-	clusterScoped := false
-	if a.store.GetKind() == esv1beta1.ClusterSecretStoreKind {
-		clusterScoped = true
-	}
-	cid, err := a.secretKeyRef(ctx, a.namespace, *a.provider.AuthSecretRef.ClientID, clusterScoped)
+	clientID, err := resolvers.SecretKeyRef(
+		ctx,
+		a.crClient,
+		a.store.GetKind(),
+		a.namespace, a.provider.AuthSecretRef.ClientID)
 	if err != nil {
 		return nil, err
 	}
-	csec, err := a.secretKeyRef(ctx, a.namespace, *a.provider.AuthSecretRef.ClientSecret, clusterScoped)
+	clientSecret, err := resolvers.SecretKeyRef(
+		ctx,
+		a.crClient,
+		a.store.GetKind(),
+		a.namespace, a.provider.AuthSecretRef.ClientSecret)
 	if err != nil {
 		return nil, err
 	}
-	clientCredentialsConfig := kvauth.NewClientCredentialsConfig(cid, csec, *a.provider.TenantID)
+	clientCredentialsConfig := kvauth.NewClientCredentialsConfig(clientID, clientSecret, *a.provider.TenantID)
 	clientCredentialsConfig.Resource = kvResourceForProviderConfig(a.provider.EnvironmentType)
 	clientCredentialsConfig.AADEndpoint = AadEndpointForType(a.provider.EnvironmentType)
 	return clientCredentialsConfig.Authorizer()
 }
 
-// secretKeyRef fetch a secret key.
-func (a *Azure) secretKeyRef(ctx context.Context, namespace string, secretRef smmeta.SecretKeySelector, clusterScoped bool) (string, error) {
-	var secret corev1.Secret
-	ref := types.NamespacedName{
-		Name:      secretRef.Name,
-		Namespace: namespace,
-	}
-	if clusterScoped && secretRef.Namespace != nil {
-		ref.Namespace = *secretRef.Namespace
-	}
-	err := a.crClient.Get(ctx, ref, &secret)
-	if err != nil {
-		return "", fmt.Errorf(errFindSecret, ref.Namespace, ref.Name, err)
-	}
-	keyBytes, ok := secret.Data[secretRef.Key]
-	if !ok {
-		return "", fmt.Errorf(errFindDataKey, secretRef.Key, secretRef.Name, namespace)
-	}
-	value := strings.TrimSpace(string(keyBytes))
-	return value, nil
-}
-
 func (a *Azure) Close(_ context.Context) error {
 	return nil
 }

+ 2 - 2
pkg/provider/azure/keyvault/keyvault_auth_test.go

@@ -244,7 +244,7 @@ func TestAuth(t *testing.T) {
 		},
 		{
 			name:   "bad config: missing secret",
-			expErr: "could not find secret default/password: secrets \"password\" not found",
+			expErr: "cannot get Kubernetes secret \"password\": secrets \"password\" not found",
 			store:  &defaultStore,
 			provider: &esv1beta1.AzureKVProvider{
 				AuthType: &authType,
@@ -258,7 +258,7 @@ func TestAuth(t *testing.T) {
 		},
 		{
 			name:   "cluster secret store",
-			expErr: "could not find secret foo/password: secrets \"password\" not found",
+			expErr: "cannot get Kubernetes secret \"password\": secrets \"password\" not found",
 			store: &esv1beta1.ClusterSecretStore{
 				TypeMeta: metav1.TypeMeta{
 					Kind: esv1beta1.ClusterSecretStoreKind,

+ 7 - 1
pkg/provider/conjur/auth_jwt.go

@@ -27,6 +27,7 @@ import (
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 const JwtLifespan = 600 // 10 minutes
@@ -46,7 +47,12 @@ func (p *Client) getJWTToken(ctx context.Context, conjurJWTConfig *esv1beta1.Con
 			tokenRef = conjurJWTConfig.SecretRef.DeepCopy()
 			tokenRef.Key = "token"
 		}
-		jwtToken, err := p.secretKeyRef(ctx, tokenRef)
+		jwtToken, err := resolvers.SecretKeyRef(
+			ctx,
+			p.kube,
+			p.StoreKind,
+			p.namespace,
+			tokenRef)
 		if err != nil {
 			return "", err
 		}

+ 28 - 38
pkg/provider/conjur/provider.go

@@ -32,6 +32,7 @@ import (
 	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
 	"github.com/external-secrets/external-secrets/pkg/provider/conjur/util"
 	"github.com/external-secrets/external-secrets/pkg/utils"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 var (
@@ -109,13 +110,22 @@ func (p *Client) GetConjurClient(ctx context.Context) (SecretsClient, error) {
 		SSLCert:      cert,
 	}
 
-	if prov.Auth.Apikey != nil {
-		config.Account = prov.Auth.Apikey.Account
-		conjUser, secErr := p.secretKeyRef(ctx, prov.Auth.Apikey.UserRef)
+	if prov.Auth.APIKey != nil {
+		config.Account = prov.Auth.APIKey.Account
+		conjUser, secErr := resolvers.SecretKeyRef(
+			ctx,
+			p.kube,
+			p.StoreKind,
+			p.namespace, prov.Auth.APIKey.UserRef)
 		if secErr != nil {
 			return nil, fmt.Errorf(errBadServiceUser, secErr)
 		}
-		conjAPIKey, secErr := p.secretKeyRef(ctx, prov.Auth.Apikey.APIKeyRef)
+		conjAPIKey, secErr := resolvers.SecretKeyRef(
+			ctx,
+			p.kube,
+			p.StoreKind,
+			p.namespace,
+			prov.Auth.APIKey.APIKeyRef)
 		if secErr != nil {
 			return nil, fmt.Errorf(errBadServiceAPIKey, secErr)
 		}
@@ -224,20 +234,20 @@ func (c *Provider) ValidateStore(store esv1beta1.GenericStore) error {
 	if prov.URL == "" {
 		return fmt.Errorf("conjur URL cannot be empty")
 	}
-	if prov.Auth.Apikey != nil {
-		if prov.Auth.Apikey.Account == "" {
+	if prov.Auth.APIKey != nil {
+		if prov.Auth.APIKey.Account == "" {
 			return fmt.Errorf("missing Auth.ApiKey.Account")
 		}
-		if prov.Auth.Apikey.UserRef == nil {
+		if prov.Auth.APIKey.UserRef == nil {
 			return fmt.Errorf("missing Auth.Apikey.UserRef")
 		}
-		if prov.Auth.Apikey.APIKeyRef == nil {
+		if prov.Auth.APIKey.APIKeyRef == nil {
 			return fmt.Errorf("missing Auth.Apikey.ApiKeyRef")
 		}
-		if err := utils.ValidateReferentSecretSelector(store, *prov.Auth.Apikey.UserRef); err != nil {
+		if err := utils.ValidateReferentSecretSelector(store, *prov.Auth.APIKey.UserRef); err != nil {
 			return fmt.Errorf("invalid Auth.Apikey.UserRef: %w", err)
 		}
-		if err := utils.ValidateReferentSecretSelector(store, *prov.Auth.Apikey.APIKeyRef); err != nil {
+		if err := utils.ValidateReferentSecretSelector(store, *prov.Auth.APIKey.APIKeyRef); err != nil {
 			return fmt.Errorf("invalid Auth.Apikey.ApiKeyRef: %w", err)
 		}
 	}
@@ -265,7 +275,7 @@ func (c *Provider) ValidateStore(store esv1beta1.GenericStore) error {
 	}
 
 	// At least one auth must be configured
-	if prov.Auth.Apikey == nil && prov.Auth.Jwt == nil {
+	if prov.Auth.APIKey == nil && prov.Auth.Jwt == nil {
 		return fmt.Errorf("missing Auth.* configuration")
 	}
 
@@ -277,32 +287,7 @@ func (c *Provider) Capabilities() esv1beta1.SecretStoreCapabilities {
 	return esv1beta1.SecretStoreReadOnly
 }
 
-func (p *Client) secretKeyRef(ctx context.Context, secretRef *esmeta.SecretKeySelector) (string, error) {
-	secret := &corev1.Secret{}
-	ref := client.ObjectKey{
-		Namespace: p.namespace,
-		Name:      secretRef.Name,
-	}
-	if (p.StoreKind == esv1beta1.ClusterSecretStoreKind) &&
-		(secretRef.Namespace != nil) {
-		ref.Namespace = *secretRef.Namespace
-	}
-	err := p.kube.Get(ctx, ref, secret)
-	if err != nil {
-		return "", err
-	}
-
-	keyBytes, ok := secret.Data[secretRef.Key]
-	if !ok {
-		return "", err
-	}
-
-	value := string(keyBytes)
-	valueStr := strings.TrimSpace(value)
-	return valueStr, nil
-}
-
-// configMapKeyRef returns the value of a key in a configmap.
+// configMapKeyRef returns the value of a key in a ConfigMap.
 func (p *Client) configMapKeyRef(ctx context.Context, cmRef *esmeta.SecretKeySelector) (string, error) {
 	configMap := &corev1.ConfigMap{}
 	ref := client.ObjectKey{
@@ -349,7 +334,12 @@ func (p *Client) getCA(ctx context.Context, provider *esv1beta1.ConjurProvider)
 				Namespace: provider.CAProvider.Namespace,
 				Key:       provider.CAProvider.Key,
 			}
-			ca, err = p.secretKeyRef(ctx, &keySelector)
+			ca, err = resolvers.SecretKeyRef(
+				ctx,
+				p.kube,
+				p.StoreKind,
+				p.namespace,
+				&keySelector)
 			if err != nil {
 				return "", fmt.Errorf(errUnableToFetchCAProviderSecret, err)
 			}

+ 2 - 2
pkg/provider/conjur/provider_test.go

@@ -351,7 +351,7 @@ func makeAPIKeySecretStore(svcURL, svcUser, svcApikey, svcAccount string) *esv1b
 				Conjur: &esv1beta1.ConjurProvider{
 					URL: svcURL,
 					Auth: esv1beta1.ConjurAuth{
-						Apikey: &esv1beta1.ConjurApikey{
+						APIKey: &esv1beta1.ConjurAPIKey{
 							Account:   svcAccount,
 							UserRef:   uref,
 							APIKeyRef: aref,
@@ -465,7 +465,7 @@ func makeFakeCASource(kind, caData string) kclient.Object {
 				Namespace: "default",
 			},
 			Data: map[string][]byte{
-				"conjur-cert": []byte(caData),
+				"ca": []byte(caData),
 			},
 		}
 	}

+ 10 - 27
pkg/provider/delinea/provider.go

@@ -17,14 +17,13 @@ package delinea
 import (
 	"context"
 	"errors"
-	"fmt"
 
 	"github.com/DelineaXPM/dsv-sdk-go/v2/vault"
-	corev1 "k8s.io/api/core/v1"
 	kubeClient "sigs.k8s.io/controller-runtime/pkg/client"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	"github.com/external-secrets/external-secrets/pkg/utils"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 var (
@@ -38,8 +37,6 @@ var (
 	errMissingSecretName             = errors.New("must specify a secret name")
 	errMissingSecretKey              = errors.New("must specify a secret key")
 	errClusterStoreRequiresNamespace = errors.New("when using a ClusterSecretStore, namespaces must be explicitly set")
-
-	errNoSuchKeyFmt = "no such key in secret: %q"
 )
 
 type Provider struct{}
@@ -62,12 +59,12 @@ func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore,
 		return nil, errClusterStoreRequiresNamespace
 	}
 
-	clientID, err := loadConfigSecret(ctx, cfg.ClientID, kube, namespace)
+	clientID, err := loadConfigSecret(ctx, store.GetKind(), cfg.ClientID, kube, namespace)
 	if err != nil {
 		return nil, err
 	}
 
-	clientSecret, err := loadConfigSecret(ctx, cfg.ClientSecret, kube, namespace)
+	clientSecret, err := loadConfigSecret(ctx, store.GetKind(), cfg.ClientSecret, kube, namespace)
 	if err != nil {
 		return nil, err
 	}
@@ -90,33 +87,19 @@ func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore,
 	}, nil
 }
 
-func loadConfigSecret(ctx context.Context, ref *esv1beta1.DelineaProviderSecretRef, kube kubeClient.Client, defaultNamespace string) (string, error) {
+func loadConfigSecret(
+	ctx context.Context,
+	storeKind string,
+	ref *esv1beta1.DelineaProviderSecretRef,
+	kube kubeClient.Client,
+	namespace string) (string, error) {
 	if ref.SecretRef == nil {
 		return ref.Value, nil
 	}
-
 	if err := validateSecretRef(ref); err != nil {
 		return "", err
 	}
-
-	namespace := defaultNamespace
-	if ref.SecretRef.Namespace != nil {
-		namespace = *ref.SecretRef.Namespace
-	}
-
-	objKey := kubeClient.ObjectKey{Namespace: namespace, Name: ref.SecretRef.Name}
-	secret := corev1.Secret{}
-	err := kube.Get(ctx, objKey, &secret)
-	if err != nil {
-		return "", err
-	}
-
-	value, ok := secret.Data[ref.SecretRef.Key]
-	if !ok {
-		return "", fmt.Errorf(errNoSuchKeyFmt, ref.SecretRef.Key)
-	}
-
-	return string(value), nil
+	return resolvers.SecretKeyRef(ctx, kube, storeKind, namespace, ref.SecretRef)
 }
 
 func validateStoreSecretRef(store esv1beta1.GenericStore, ref *esv1beta1.DelineaProviderSecretRef) error {

+ 1 - 2
pkg/provider/delinea/provider_test.go

@@ -15,7 +15,6 @@ package delinea
 
 import (
 	"context"
-	"fmt"
 	"testing"
 
 	"github.com/DelineaXPM/dsv-sdk-go/v2/vault"
@@ -283,7 +282,7 @@ func TestNewClient(t *testing.T) {
 			},
 			kube: clientfake.NewClientBuilder().WithObjects(clientSecret).Build(),
 			errCheck: func(t *testing.T, err error) {
-				assert.EqualError(t, err, fmt.Sprintf(errNoSuchKeyFmt, "typo"))
+				assert.EqualError(t, err, "cannot find secret data for key: \"typo\"")
 			},
 		},
 		"valid secret refs": {

+ 9 - 30
pkg/provider/doppler/client.go

@@ -23,13 +23,13 @@ import (
 	"time"
 
 	corev1 "k8s.io/api/core/v1"
-	"k8s.io/apimachinery/pkg/types"
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	"github.com/external-secrets/external-secrets/pkg/find"
 	dClient "github.com/external-secrets/external-secrets/pkg/provider/doppler/client"
 	"github.com/external-secrets/external-secrets/pkg/utils"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 const (
@@ -41,8 +41,6 @@ const (
 	secretsDownloadFileKey                             = "DOPPLER_SECRETS_FILE"
 	errDopplerTokenSecretName                          = "missing auth.secretRef.dopplerToken.name"
 	errInvalidClusterStoreMissingDopplerTokenNamespace = "missing auth.secretRef.dopplerToken.namespace"
-	errFetchDopplerTokenSecret                         = "unable to find find DopplerToken secret: %w"
-	errMissingDopplerToken                             = "auth.secretRef.dopplerToken.key '%s' not found in secret '%s'"
 )
 
 type Client struct {
@@ -68,35 +66,16 @@ type SecretsClientInterface interface {
 }
 
 func (c *Client) setAuth(ctx context.Context) error {
-	credentialsSecret := &corev1.Secret{}
-	credentialsSecretName := c.store.Auth.SecretRef.DopplerToken.Name
-	if credentialsSecretName == "" {
-		return fmt.Errorf(errDopplerTokenSecretName)
-	}
-	objectKey := types.NamespacedName{
-		Name:      credentialsSecretName,
-		Namespace: c.namespace,
-	}
-	// only ClusterStore is allowed to set namespace (and then it's required)
-	if c.storeKind == esv1beta1.ClusterSecretStoreKind {
-		if c.store.Auth.SecretRef.DopplerToken.Namespace == nil {
-			return fmt.Errorf(errInvalidClusterStoreMissingDopplerTokenNamespace)
-		}
-		objectKey.Namespace = *c.store.Auth.SecretRef.DopplerToken.Namespace
-	}
-
-	err := c.kube.Get(ctx, objectKey, credentialsSecret)
+	token, err := resolvers.SecretKeyRef(
+		ctx,
+		c.kube,
+		c.storeKind,
+		c.namespace,
+		&c.store.Auth.SecretRef.DopplerToken)
 	if err != nil {
-		return fmt.Errorf(errFetchDopplerTokenSecret, err)
+		return err
 	}
-
-	dopplerToken := credentialsSecret.Data[c.store.Auth.SecretRef.DopplerToken.Key]
-	if (dopplerToken == nil) || (len(dopplerToken) == 0) {
-		return fmt.Errorf(errMissingDopplerToken, c.store.Auth.SecretRef.DopplerToken.Key, credentialsSecretName)
-	}
-
-	c.dopplerToken = string(dopplerToken)
-
+	c.dopplerToken = token
 	return nil
 }
 

+ 13 - 21
pkg/provider/gcp/secretmanager/auth.go

@@ -19,15 +19,14 @@ import (
 
 	"golang.org/x/oauth2"
 	"golang.org/x/oauth2/google"
-	v1 "k8s.io/api/core/v1"
-	"k8s.io/apimachinery/pkg/types"
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
-func NewTokenSource(ctx context.Context, auth esv1beta1.GCPSMAuth, projectID string, isClusterKind bool, kube kclient.Client, namespace string) (oauth2.TokenSource, error) {
-	ts, err := serviceAccountTokenSource(ctx, auth, isClusterKind, kube, namespace)
+func NewTokenSource(ctx context.Context, auth esv1beta1.GCPSMAuth, projectID, storeKind string, kube kclient.Client, namespace string) (oauth2.TokenSource, error) {
+	ts, err := serviceAccountTokenSource(ctx, auth, storeKind, kube, namespace)
 	if ts != nil || err != nil {
 		return ts, err
 	}
@@ -36,6 +35,7 @@ func NewTokenSource(ctx context.Context, auth esv1beta1.GCPSMAuth, projectID str
 		return nil, fmt.Errorf("unable to initialize workload identity")
 	}
 	defer wi.Close()
+	isClusterKind := storeKind == esv1beta1.ClusterSecretStoreKind
 	ts, err = wi.TokenSource(ctx, auth, isClusterKind, kube, namespace)
 	if ts != nil || err != nil {
 		return ts, err
@@ -43,29 +43,21 @@ func NewTokenSource(ctx context.Context, auth esv1beta1.GCPSMAuth, projectID str
 	return google.DefaultTokenSource(ctx, CloudPlatformRole)
 }
 
-func serviceAccountTokenSource(ctx context.Context, auth esv1beta1.GCPSMAuth, isClusterKind bool, kube kclient.Client, namespace string) (oauth2.TokenSource, error) {
+func serviceAccountTokenSource(ctx context.Context, auth esv1beta1.GCPSMAuth, storeKind string, kube kclient.Client, namespace string) (oauth2.TokenSource, error) {
 	sr := auth.SecretRef
 	if sr == nil {
 		return nil, nil
 	}
-	credentialsSecret := &v1.Secret{}
-	credentialsSecretName := sr.SecretAccessKey.Name
-	objectKey := types.NamespacedName{
-		Name:      credentialsSecretName,
-		Namespace: namespace,
-	}
-	if isClusterKind && sr.SecretAccessKey.Namespace != nil {
-		objectKey.Namespace = *sr.SecretAccessKey.Namespace
-	}
-	err := kube.Get(ctx, objectKey, credentialsSecret)
+	credentials, err := resolvers.SecretKeyRef(
+		ctx,
+		kube,
+		storeKind,
+		namespace,
+		&auth.SecretRef.SecretAccessKey)
 	if err != nil {
-		return nil, fmt.Errorf(errFetchSAKSecret, err)
-	}
-	credentials := credentialsSecret.Data[sr.SecretAccessKey.Key]
-	if (credentials == nil) || (len(credentials) == 0) {
-		return nil, fmt.Errorf(errMissingSAK)
+		return nil, err
 	}
-	config, err := google.JWTConfigFromJSON(credentials, CloudPlatformRole)
+	config, err := google.JWTConfigFromJSON([]byte(credentials), CloudPlatformRole)
 	if err != nil {
 		return nil, fmt.Errorf(errUnableProcessJSONCredentials, err)
 	}

+ 0 - 1
pkg/provider/gcp/secretmanager/client.go

@@ -50,7 +50,6 @@ const (
 	errClientClose                  = "unable to close SecretManager client: %w"
 	errMissingStoreSpec             = "invalid: missing store spec"
 	errFetchSAKSecret               = "could not fetch SecretAccessKey secret: %w"
-	errMissingSAK                   = "missing SecretAccessKey"
 	errUnableProcessJSONCredentials = "failed to process the provided JSON credentials: %w"
 	errUnableCreateGCPSMClient      = "failed to create GCP secretmanager client: %w"
 	errUninitalizedGCPProvider      = "provider GCP is not initialized"

+ 1 - 1
pkg/provider/gcp/secretmanager/provider.go

@@ -90,7 +90,7 @@ func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore,
 		return client, nil
 	}
 
-	ts, err := NewTokenSource(ctx, gcpStore.Auth, clusterProjectID, isClusterKind, kube, namespace)
+	ts, err := NewTokenSource(ctx, gcpStore.Auth, clusterProjectID, store.GetKind(), kube, namespace)
 	if err != nil {
 		return nil, fmt.Errorf(errUnableCreateGCPSMClient, err)
 	}

+ 8 - 30
pkg/provider/gitlab/gitlab.go

@@ -25,7 +25,6 @@ import (
 	"github.com/tidwall/gjson"
 	"github.com/xanzy/go-gitlab"
 	corev1 "k8s.io/api/core/v1"
-	"k8s.io/apimachinery/pkg/types"
 	ctrl "sigs.k8s.io/controller-runtime"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
@@ -33,13 +32,13 @@ import (
 	"github.com/external-secrets/external-secrets/pkg/find"
 	"github.com/external-secrets/external-secrets/pkg/metrics"
 	"github.com/external-secrets/external-secrets/pkg/utils"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 const (
 	errGitlabCredSecretName                   = "credentials are empty"
 	errInvalidClusterStoreMissingSAKNamespace = "invalid clusterStore missing SAK namespace"
 	errFetchSAKSecret                         = "couldn't find secret on cluster: %w"
-	errMissingSAK                             = "missing credentials while setting auth"
 	errList                                   = "could not verify whether the gilabClient is valid: %w"
 	errProjectAuth                            = "gitlabClient is not allowed to get secrets for project id [%s]"
 	errGroupAuth                              = "gitlabClient is not allowed to get secrets for group id [%s]"
@@ -78,34 +77,13 @@ func (a ProjectGroupPathSorter) Less(i, j int) bool { return len(a[i].FullPath)
 var log = ctrl.Log.WithName("provider").WithName("gitlab")
 
 // Set gitlabBase credentials to Access Token.
-func (g *gitlabBase) getAuth(ctx context.Context) ([]byte, error) {
-	credentialsSecret := &corev1.Secret{}
-	credentialsSecretName := g.store.Auth.SecretRef.AccessToken.Name
-	if credentialsSecretName == "" {
-		return nil, fmt.Errorf(errGitlabCredSecretName)
-	}
-	objectKey := types.NamespacedName{
-		Name:      credentialsSecretName,
-		Namespace: g.namespace,
-	}
-	// only ClusterStore is allowed to set namespace (and then it's required)
-	if g.storeKind == esv1beta1.ClusterSecretStoreKind {
-		if g.store.Auth.SecretRef.AccessToken.Namespace == nil {
-			return nil, fmt.Errorf(errInvalidClusterStoreMissingSAKNamespace)
-		}
-		objectKey.Namespace = *g.store.Auth.SecretRef.AccessToken.Namespace
-	}
-
-	err := g.kube.Get(ctx, objectKey, credentialsSecret)
-	if err != nil {
-		return nil, fmt.Errorf(errFetchSAKSecret, err)
-	}
-
-	credentials := credentialsSecret.Data[g.store.Auth.SecretRef.AccessToken.Key]
-	if len(credentials) == 0 {
-		return nil, fmt.Errorf(errMissingSAK)
-	}
-	return credentials, nil
+func (g *gitlabBase) getAuth(ctx context.Context) (string, error) {
+	return resolvers.SecretKeyRef(
+		ctx,
+		g.kube,
+		g.storeKind,
+		g.namespace,
+		&g.store.Auth.SecretRef.AccessToken)
 }
 
 func (g *gitlabBase) DeleteSecret(_ context.Context, _ esv1beta1.PushSecretRemoteRef) error {

+ 2 - 2
pkg/provider/gitlab/gitlab_test.go

@@ -46,7 +46,7 @@ const (
 	groupvalue            = "groupvalue"
 	groupid               = "groupId"
 	defaultErrorMessage   = "[%d] unexpected error: [%s], expected: [%s]"
-	errMissingCredentials = "credentials are empty"
+	errMissingCredentials = "cannot get Kubernetes secret \"\": secrets \"\" not found"
 	testKey               = "testKey"
 	findTestPrefix        = "test.*"
 )
@@ -351,7 +351,7 @@ func TestNewClient(t *testing.T) {
 	store.Spec.Provider.Gitlab.Auth.SecretRef.AccessToken.Name = authorizedKeySecretName
 	store.Spec.Provider.Gitlab.Auth.SecretRef.AccessToken.Key = authorizedKeySecretKey
 	secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
-	tassert.EqualError(t, err, "couldn't find secret on cluster: secrets \"authorizedKeySecretName\" not found")
+	tassert.EqualError(t, err, "cannot get Kubernetes secret \"authorizedKeySecretName\": secrets \"authorizedKeySecretName\" not found")
 	tassert.Nil(t, secretClient)
 
 	err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, newFakeAuthorizedKey()))

+ 1 - 1
pkg/provider/gitlab/provider.go

@@ -86,7 +86,7 @@ func (g *gitlabBase) getClient(ctx context.Context, provider *esv1beta1.GitlabPr
 	// in a similar way to extend functionality of the provider
 
 	// Create a new GitLab Client using credentials and options
-	client, err := gitlab.NewClient(string(credentials), opts...)
+	client, err := gitlab.NewClient(credentials, opts...)
 	if err != nil {
 		return nil, err
 	}

+ 11 - 35
pkg/provider/ibm/provider.go

@@ -26,13 +26,13 @@ import (
 	"github.com/google/uuid"
 	"github.com/tidwall/gjson"
 	corev1 "k8s.io/api/core/v1"
-	"k8s.io/apimachinery/pkg/types"
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	"github.com/external-secrets/external-secrets/pkg/constants"
 	"github.com/external-secrets/external-secrets/pkg/metrics"
 	"github.com/external-secrets/external-secrets/pkg/utils"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 const (
@@ -51,15 +51,13 @@ const (
 	payloadConst      = "payload"
 	smAPIKeyConst     = "api_key"
 
-	errIBMClient                             = "cannot setup new ibm client: %w"
-	errIBMCredSecretName                     = "invalid IBM SecretStore resource: missing IBM APIKey"
-	errUninitalizedIBMProvider               = "provider IBM is not initialized"
-	errInvalidClusterStoreMissingSKNamespace = "invalid ClusterStore, missing namespace"
-	errFetchSAKSecret                        = "could not fetch SecretAccessKey secret: %w"
-	errMissingSAK                            = "missing SecretAccessKey"
-	errJSONSecretUnmarshal                   = "unable to unmarshal secret: %w"
-	errJSONSecretMarshal                     = "unable to marshal secret: %w"
-	errExtractingSecret                      = "unable to extract the fetched secret %s of type %s while performing %s"
+	errIBMClient               = "cannot setup new ibm client: %w"
+	errIBMCredSecretName       = "invalid IBM SecretStore resource: missing IBM APIKey"
+	errUninitalizedIBMProvider = "provider IBM is not initialized"
+	errFetchSAKSecret          = "could not fetch SecretAccessKey secret: %w"
+	errJSONSecretUnmarshal     = "unable to unmarshal secret: %w"
+	errJSONSecretMarshal       = "unable to marshal secret: %w"
+	errExtractingSecret        = "unable to extract the fetched secret %s of type %s while performing %s"
 
 	defaultCacheSize   = 100
 	defaultCacheExpiry = 1 * time.Hour
@@ -93,33 +91,11 @@ type client struct {
 }
 
 func (c *client) setAuth(ctx context.Context) error {
-	credentialsSecret := &corev1.Secret{}
-	credentialsSecretName := c.store.Auth.SecretRef.SecretAPIKey.Name
-	if credentialsSecretName == "" {
-		return fmt.Errorf(errIBMCredSecretName)
-	}
-	objectKey := types.NamespacedName{
-		Name:      credentialsSecretName,
-		Namespace: c.namespace,
-	}
-
-	// only ClusterStore is allowed to set namespace (and then it's required)
-	if c.storeKind == esv1beta1.ClusterSecretStoreKind {
-		if c.store.Auth.SecretRef.SecretAPIKey.Namespace == nil {
-			return fmt.Errorf(errInvalidClusterStoreMissingSKNamespace)
-		}
-		objectKey.Namespace = *c.store.Auth.SecretRef.SecretAPIKey.Namespace
-	}
-
-	err := c.kube.Get(ctx, objectKey, credentialsSecret)
+	apiKey, err := resolvers.SecretKeyRef(ctx, c.kube, c.storeKind, c.namespace, &c.store.Auth.SecretRef.SecretAPIKey)
 	if err != nil {
-		return fmt.Errorf(errFetchSAKSecret, err)
-	}
-
-	c.credentials = credentialsSecret.Data[c.store.Auth.SecretRef.SecretAPIKey.Key]
-	if (c.credentials == nil) || (len(c.credentials) == 0) {
-		return fmt.Errorf(errMissingSAK)
+		return err
 	}
+	c.credentials = []byte(apiKey)
 	return nil
 }
 

+ 9 - 33
pkg/provider/keepersecurity/provider.go

@@ -19,12 +19,11 @@ import (
 
 	ksm "github.com/keeper-security/secrets-manager-go/core"
 	"github.com/keeper-security/secrets-manager-go/core/logger"
-	v1 "k8s.io/api/core/v1"
-	"k8s.io/apimachinery/pkg/types"
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	"github.com/external-secrets/external-secrets/pkg/utils"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 const (
@@ -66,8 +65,7 @@ func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore,
 
 	keeperStore := storeSpec.Provider.KeeperSecurity
 
-	isClusterKind := store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind
-	clientConfig, err := getKeeperSecurityAuth(ctx, keeperStore, kube, isClusterKind, namespace)
+	clientConfig, err := getKeeperSecurityAuth(ctx, keeperStore, kube, store.GetKind(), namespace)
 	if err != nil {
 		return nil, fmt.Errorf(errKeeperSecurityUnableToCreateConfig, err)
 	}
@@ -112,33 +110,11 @@ func (p *Provider) ValidateStore(store esv1beta1.GenericStore) error {
 	return nil
 }
 
-func getKeeperSecurityAuth(ctx context.Context, store *esv1beta1.KeeperSecurityProvider, kube kclient.Client, isClusterKind bool, namespace string) (string, error) {
-	auth := store.Auth
-
-	credentialsSecret := &v1.Secret{}
-	credentialsSecretName := auth.Name
-	objectKey := types.NamespacedName{
-		Name:      credentialsSecretName,
-		Namespace: namespace,
-	}
-
-	// only ClusterStore is allowed to set namespace (and then it's required)
-	if isClusterKind {
-		if credentialsSecretName != "" && auth.Namespace == nil {
-			return "", fmt.Errorf(errInvalidClusterStoreMissingK8sSecretNamespace)
-		} else if credentialsSecretName != "" {
-			objectKey.Namespace = *auth.Namespace
-		}
-	}
-
-	err := kube.Get(ctx, objectKey, credentialsSecret)
-	if err != nil {
-		return "", fmt.Errorf(errFetchK8sSecret, err)
-	}
-	data := credentialsSecret.Data[auth.Key]
-	if (data == nil) || (len(data) == 0) {
-		return "", fmt.Errorf(errMissingK8sSecretKey, auth.Key)
-	}
-
-	return string(data), nil
+func getKeeperSecurityAuth(ctx context.Context, store *esv1beta1.KeeperSecurityProvider, kube kclient.Client, storeKind, namespace string) (string, error) {
+	return resolvers.SecretKeyRef(
+		ctx,
+		kube,
+		storeKind,
+		namespace,
+		&store.Auth)
 }

+ 11 - 23
pkg/provider/kubernetes/auth.go

@@ -25,6 +25,7 @@ import (
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 const (
@@ -128,31 +129,18 @@ func (c *Client) serviceAccountToken(ctx context.Context, serviceAccountRef *esm
 	return []byte(tr.Status.Token), nil
 }
 
-func (c *Client) fetchSecretKey(ctx context.Context, key esmeta.SecretKeySelector) ([]byte, error) {
-	keySecret := &corev1.Secret{}
-	objectKey := types.NamespacedName{
-		Name:      key.Name,
-		Namespace: c.namespace,
-	}
-	// only ClusterStore is allowed to set namespace (and then it's required)
-	if c.storeKind == esv1beta1.ClusterSecretStoreKind {
-		if key.Namespace == nil {
-			return nil, fmt.Errorf(errInvalidClusterStoreMissingNamespace)
-		}
-		objectKey.Namespace = *key.Namespace
-	}
-	err := c.ctrlClient.Get(ctx, objectKey, keySecret)
+func (c *Client) fetchSecretKey(ctx context.Context, ref esmeta.SecretKeySelector) ([]byte, error) {
+	secret, err := resolvers.SecretKeyRef(
+		ctx,
+		c.ctrlClient,
+		c.storeKind,
+		c.namespace,
+		&ref,
+	)
 	if err != nil {
-		return nil, fmt.Errorf(errFetchCredentials, err)
-	}
-	val, ok := keySecret.Data[key.Key]
-	if !ok {
-		return nil, fmt.Errorf(errMissingCredentials, key.Key)
-	}
-	if len(val) == 0 {
-		return nil, fmt.Errorf(errEmptyKey, key.Key)
+		return nil, err
 	}
-	return val, nil
+	return []byte(secret), nil
 }
 
 func (c *Client) fetchConfigMapKey(ctx context.Context, key esmeta.SecretKeySelector) ([]byte, error) {

+ 10 - 21
pkg/provider/onepassword/onepassword.go

@@ -23,12 +23,12 @@ import (
 	"github.com/1Password/connect-sdk-go/connect"
 	"github.com/1Password/connect-sdk-go/onepassword"
 	corev1 "k8s.io/api/core/v1"
-	"k8s.io/apimachinery/pkg/types"
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	"github.com/external-secrets/external-secrets/pkg/find"
 	"github.com/external-secrets/external-secrets/pkg/utils"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 const (
@@ -95,29 +95,18 @@ func (provider *ProviderOnePassword) Capabilities() esv1beta1.SecretStoreCapabil
 // NewClient constructs a 1Password Provider.
 func (provider *ProviderOnePassword) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	config := store.GetSpec().Provider.OnePassword
-
-	credentialsSecret := &corev1.Secret{}
-	objectKey := types.NamespacedName{
-		Name:      config.Auth.SecretRef.ConnectToken.Name,
-		Namespace: namespace,
-	}
-
-	// only ClusterSecretStore is allowed to set namespace (and then it's required)
-	if store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind {
-		objectKey.Namespace = *config.Auth.SecretRef.ConnectToken.Namespace
-	}
-
-	err := kube.Get(ctx, objectKey, credentialsSecret)
+	token, err := resolvers.SecretKeyRef(
+		ctx,
+		kube,
+		store.GetKind(),
+		namespace,
+		&config.Auth.SecretRef.ConnectToken,
+	)
 	if err != nil {
-		return nil, fmt.Errorf(errFetchK8sSecret, err)
-	}
-	token := credentialsSecret.Data[config.Auth.SecretRef.ConnectToken.Key]
-	if (token == nil) || (len(token) == 0) {
-		return nil, fmt.Errorf(errMissingToken)
+		return nil, err
 	}
-	provider.client = connect.NewClientWithUserAgent(config.ConnectHost, string(token), userAgent)
+	provider.client = connect.NewClientWithUserAgent(config.ConnectHost, token, userAgent)
 	provider.vaults = config.Vaults
-
 	return provider, nil
 }
 

+ 22 - 33
pkg/provider/oracle/oracle.go

@@ -32,7 +32,6 @@ import (
 	"github.com/oracle/oci-go-sdk/v65/vault"
 	"github.com/tidwall/gjson"
 	corev1 "k8s.io/api/core/v1"
-	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/client-go/kubernetes"
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
 	ctrlcfg "sigs.k8s.io/controller-runtime/pkg/client/config"
@@ -40,23 +39,23 @@ import (
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
 	"github.com/external-secrets/external-secrets/pkg/utils"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 const (
-	errOracleClient                          = "cannot setup new oracle client: %w"
-	errORACLECredSecretName                  = "invalid oracle SecretStore resource: missing oracle APIKey"
-	errUninitalizedOracleProvider            = "provider oracle is not initialized"
-	errInvalidClusterStoreMissingSKNamespace = "invalid ClusterStore, missing namespace"
-	errFetchSAKSecret                        = "could not fetch SecretAccessKey secret: %w"
-	errMissingPK                             = "missing PrivateKey"
-	errMissingUser                           = "missing User ID"
-	errMissingTenancy                        = "missing Tenancy ID"
-	errMissingRegion                         = "missing Region"
-	errMissingFingerprint                    = "missing Fingerprint"
-	errMissingVault                          = "missing Vault"
-	errJSONSecretUnmarshal                   = "unable to unmarshal secret: %w"
-	errMissingKey                            = "missing Key in secret: %s"
-	errUnexpectedContent                     = "unexpected secret bundle content"
+	errOracleClient               = "cannot setup new oracle client: %w"
+	errORACLECredSecretName       = "invalid oracle SecretStore resource: missing oracle APIKey"
+	errUninitalizedOracleProvider = "provider oracle is not initialized"
+	errFetchSAKSecret             = "could not fetch SecretAccessKey secret: %w"
+	errMissingPK                  = "missing PrivateKey"
+	errMissingUser                = "missing User ID"
+	errMissingTenancy             = "missing Tenancy ID"
+	errMissingRegion              = "missing Region"
+	errMissingFingerprint         = "missing Fingerprint"
+	errMissingVault               = "missing Vault"
+	errJSONSecretUnmarshal        = "unable to unmarshal secret: %w"
+	errMissingKey                 = "missing Key in secret: %s"
+	errUnexpectedContent          = "unexpected secret bundle content"
 )
 
 // https://github.com/external-secrets/external-secrets/issues/644
@@ -398,27 +397,17 @@ func getSecretData(ctx context.Context, kube kclient.Client, namespace, storeKin
 	if secretRef.Name == "" {
 		return "", fmt.Errorf(errORACLECredSecretName)
 	}
-
-	objectKey := types.NamespacedName{
-		Name:      secretRef.Name,
-		Namespace: namespace,
-	}
-
-	// only ClusterStore is allowed to set namespace (and then it's required)
-	if storeKind == esv1beta1.ClusterSecretStoreKind {
-		if secretRef.Namespace == nil {
-			return "", fmt.Errorf(errInvalidClusterStoreMissingSKNamespace)
-		}
-		objectKey.Namespace = *secretRef.Namespace
-	}
-
-	secret := corev1.Secret{}
-	err := kube.Get(ctx, objectKey, &secret)
+	secret, err := resolvers.SecretKeyRef(
+		ctx,
+		kube,
+		storeKind,
+		namespace,
+		&secretRef,
+	)
 	if err != nil {
 		return "", fmt.Errorf(errFetchSAKSecret, err)
 	}
-
-	return string(secret.Data[secretRef.Key]), nil
+	return secret, nil
 }
 
 func getUserAuthConfigurationProvider(ctx context.Context, kube kclient.Client, store *esv1beta1.OracleProvider, namespace, storeKind, region string) (common.ConfigurationProvider, error) {

+ 1 - 1
pkg/provider/oracle/oracle_test.go

@@ -440,7 +440,7 @@ func TestVaultManagementService_NewClient(t *testing.T) {
 					},
 				},
 			},
-			expectedErr: `could not fetch SecretAccessKey secret: secrets "non-existing-secret"`,
+			expectedErr: `cannot get Kubernetes secret "non-existing-secret": secrets "non-existing-secret" not found`,
 		},
 		{
 			desc: "invalid retry interval",

+ 11 - 36
pkg/provider/scaleway/provider.go

@@ -21,12 +21,12 @@ import (
 	smapi "github.com/scaleway/scaleway-sdk-go/api/secret/v1alpha1"
 	"github.com/scaleway/scaleway-sdk-go/scw"
 	"github.com/scaleway/scaleway-sdk-go/validation"
-	corev1 "k8s.io/api/core/v1"
 	ctrl "sigs.k8s.io/controller-runtime"
 	kubeClient "sigs.k8s.io/controller-runtime/pkg/client"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	"github.com/external-secrets/external-secrets/pkg/utils"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 var (
@@ -52,12 +52,12 @@ func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore,
 		return nil, fmt.Errorf("when using a ClusterSecretStore, namespaces must be explicitly set")
 	}
 
-	accessKey, err := loadConfigSecret(ctx, cfg.AccessKey, kube, namespace)
+	accessKey, err := loadConfigSecret(ctx, cfg.AccessKey, kube, namespace, store.GetKind())
 	if err != nil {
 		return nil, err
 	}
 
-	secretKey, err := loadConfigSecret(ctx, cfg.SecretKey, kube, namespace)
+	secretKey, err := loadConfigSecret(ctx, cfg.SecretKey, kube, namespace, store.GetKind())
 	if err != nil {
 		return nil, err
 	}
@@ -80,42 +80,17 @@ func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore,
 	}, nil
 }
 
-func loadConfigSecret(ctx context.Context, ref *esv1beta1.ScalewayProviderSecretRef, kube kubeClient.Client, defaultNamespace string) (string, error) {
+func loadConfigSecret(ctx context.Context, ref *esv1beta1.ScalewayProviderSecretRef, kube kubeClient.Client, defaultNamespace, storeKind string) (string, error) {
 	if ref.SecretRef == nil {
 		return ref.Value, nil
 	}
-
-	namespace := defaultNamespace
-	if ref.SecretRef.Namespace != nil {
-		namespace = *ref.SecretRef.Namespace
-	}
-
-	if ref.SecretRef.Name == "" {
-		return "", fmt.Errorf("must specify a value or a reference to a secret")
-	}
-
-	if ref.SecretRef.Key == "" {
-		return "", fmt.Errorf("must specify a secret key")
-	}
-
-	objKey := kubeClient.ObjectKey{
-		Namespace: namespace,
-		Name:      ref.SecretRef.Name,
-	}
-
-	secret := corev1.Secret{}
-
-	err := kube.Get(ctx, objKey, &secret)
-	if err != nil {
-		return "", err
-	}
-
-	value, ok := secret.Data[ref.SecretRef.Key]
-	if !ok {
-		return "", fmt.Errorf("no such key in secret: %v", ref.SecretRef.Key)
-	}
-
-	return string(value), nil
+	return resolvers.SecretKeyRef(
+		ctx,
+		kube,
+		storeKind,
+		defaultNamespace,
+		ref.SecretRef,
+	)
 }
 
 func validateSecretRef(store esv1beta1.GenericStore, ref *esv1beta1.ScalewayProviderSecretRef) error {

+ 9 - 2
pkg/provider/senhasegura/auth/iso.go

@@ -28,6 +28,7 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 type ISOInterface interface {
@@ -76,12 +77,18 @@ func Authenticate(ctx context.Context, store esv1beta1.GenericStore, provider *e
 IsoSessionFromSecretRef initialize an ISO OAuth2 flow with .spec.provider.senhasegura.auth.isoSecretRef parameters.
 */
 func (s *SenhaseguraIsoSession) IsoSessionFromSecretRef(ctx context.Context, provider *esv1beta1.SenhaseguraProvider, store esv1beta1.GenericStore, kube client.Client, namespace string) (*SenhaseguraIsoSession, error) {
-	clientSecret, err := getKubernetesSecret(ctx, provider.Auth.ClientSecret, store, kube, namespace)
+	secret, err := resolvers.SecretKeyRef(
+		ctx,
+		kube,
+		store.GetKind(),
+		namespace,
+		&provider.Auth.ClientSecret,
+	)
 	if err != nil {
 		return &SenhaseguraIsoSession{}, err
 	}
 
-	isoToken, err := s.GetIsoToken(provider.Auth.ClientID, clientSecret, provider.URL, provider.IgnoreSslCertificate)
+	isoToken, err := s.GetIsoToken(provider.Auth.ClientID, secret, provider.URL, provider.IgnoreSslCertificate)
 	if err != nil {
 		return &SenhaseguraIsoSession{}, err
 	}

+ 0 - 57
pkg/provider/senhasegura/auth/kubernetes_secret.go

@@ -1,57 +0,0 @@
-/*
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package auth
-
-import (
-	"context"
-	"fmt"
-
-	v1 "k8s.io/api/core/v1"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-
-	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
-	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
-)
-
-const (
-	errRequiredNamespaceNotFound   = "invalid ClusterSecretStore: missing namespace in %s"
-	errCannotFetchKubernetesSecret = "could not fetch Kubernetes secret %s"
-)
-
-/*
-getKubernetesSecret get Kubernetes Secret based on object parameter in namespace where ESO is installed or another, if ClusterSecretStore is used.
-*/
-func getKubernetesSecret(ctx context.Context, object esmeta.SecretKeySelector, store esv1beta1.GenericStore, kube client.Client, namespace string) (string, error) {
-	ke := client.ObjectKey{
-		Name:      object.Name,
-		Namespace: namespace, // Default to ExternalSecret namespace
-	}
-
-	// Only ClusterStore is allowed to set namespace (and then it's required)
-	if store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind {
-		if object.Namespace == nil {
-			return "", fmt.Errorf(errRequiredNamespaceNotFound, object.Key)
-		}
-		ke.Namespace = *object.Namespace
-	}
-
-	secret := v1.Secret{}
-	err := kube.Get(ctx, ke, &secret)
-	if err != nil {
-		return "", fmt.Errorf(errCannotFetchKubernetesSecret, object.Name)
-	}
-
-	return string(secret.Data[object.Key]), nil
-}

+ 27 - 55
pkg/provider/vault/iamauth/iamauth.go

@@ -41,6 +41,7 @@ import (
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	"github.com/external-secrets/external-secrets/pkg/provider/vault/util"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 var (
@@ -54,14 +55,6 @@ const (
 
 	STSEndpointEnv                = "AWS_STS_ENDPOINT"
 	AWSWebIdentityTokenFileEnvVar = "AWS_WEB_IDENTITY_TOKEN_FILE"
-
-	errInvalidClusterStoreMissingAKIDNamespace = "invalid ClusterSecretStore: missing AWS AccessKeyID Namespace"
-	errInvalidClusterStoreMissingSAKNamespace  = "invalid ClusterSecretStore: missing AWS SecretAccessKey Namespace"
-	errFetchAKIDSecret                         = "could not fetch accessKeyID secret: %w"
-	errFetchSAKSecret                          = "could not fetch SecretAccessKey secret: %w"
-	errFetchSTSecret                           = "could not fetch SessionToken secret: %w"
-	errMissingSAK                              = "missing SecretAccessKey"
-	errMissingAKID                             = "missing AccessKeyID"
 )
 
 // DefaultJWTProvider returns a credentials.Provider that calls the AssumeRoleWithWebidentity
@@ -232,58 +225,37 @@ func CredsFromControllerServiceAccount(ctx context.Context, saname, ns, region s
 // construct a aws.Credentials object
 // The namespace of the external secret is used if the ClusterSecretStore does not specify a namespace (referentAuth)
 // If the ClusterSecretStore defines a namespace it will take precedence.
-func CredsFromSecretRef(ctx context.Context, auth esv1beta1.VaultIamAuth, isClusterKind bool, kube kclient.Client, namespace string) (*credentials.Credentials, error) {
-	ke := kclient.ObjectKey{
-		Name:      auth.SecretRef.AccessKeyID.Name,
-		Namespace: namespace,
-	}
-	if isClusterKind && auth.SecretRef.AccessKeyID.Namespace != nil {
-		ke.Namespace = *auth.SecretRef.AccessKeyID.Namespace
-	}
-	akSecret := v1.Secret{}
-	err := kube.Get(ctx, ke, &akSecret)
+func CredsFromSecretRef(ctx context.Context, auth esv1beta1.VaultIamAuth, storeKind string, kube kclient.Client, namespace string) (*credentials.Credentials, error) {
+	akid, err := resolvers.SecretKeyRef(
+		ctx,
+		kube,
+		storeKind,
+		namespace,
+		&auth.SecretRef.AccessKeyID,
+	)
 	if err != nil {
-		return nil, fmt.Errorf(errFetchAKIDSecret, err)
-	}
-	ke = kclient.ObjectKey{
-		Name:      auth.SecretRef.SecretAccessKey.Name,
-		Namespace: namespace,
-	}
-	if isClusterKind && auth.SecretRef.SecretAccessKey.Namespace != nil {
-		ke.Namespace = *auth.SecretRef.SecretAccessKey.Namespace
+		return nil, err
 	}
-	sakSecret := v1.Secret{}
-	err = kube.Get(ctx, ke, &sakSecret)
+	sak, err := resolvers.SecretKeyRef(
+		ctx,
+		kube,
+		storeKind,
+		namespace,
+		&auth.SecretRef.SecretAccessKey,
+	)
 	if err != nil {
-		return nil, fmt.Errorf(errFetchSAKSecret, err)
-	}
-	sak := string(sakSecret.Data[auth.SecretRef.SecretAccessKey.Key])
-	aks := string(akSecret.Data[auth.SecretRef.AccessKeyID.Key])
-	if sak == "" {
-		return nil, fmt.Errorf(errMissingSAK)
-	}
-	if aks == "" {
-		return nil, fmt.Errorf(errMissingAKID)
-	}
-
-	var sessionToken string
-	if auth.SecretRef.SessionToken != nil {
-		ke = kclient.ObjectKey{
-			Name:      auth.SecretRef.SessionToken.Name,
-			Namespace: namespace,
-		}
-		if isClusterKind && auth.SecretRef.SessionToken.Namespace != nil {
-			ke.Namespace = *auth.SecretRef.SessionToken.Namespace
-		}
-		stSecret := v1.Secret{}
-		err = kube.Get(ctx, ke, &stSecret)
-		if err != nil {
-			return nil, fmt.Errorf(errFetchSTSecret, err)
-		}
-		sessionToken = string(stSecret.Data[auth.SecretRef.SessionToken.Key])
+		return nil, err
 	}
 
-	return credentials.NewStaticCredentials(aks, sak, sessionToken), err
+	// session token is optional
+	sessionToken, _ := resolvers.SecretKeyRef(
+		ctx,
+		kube,
+		storeKind,
+		namespace,
+		auth.SecretRef.SessionToken,
+	)
+	return credentials.NewStaticCredentials(akid, sak, sessionToken), err
 }
 
 type STSProvider func(*session.Session) stsiface.STSAPI

+ 68 - 74
pkg/provider/vault/vault.go

@@ -40,7 +40,7 @@ import (
 	authuserpass "github.com/hashicorp/vault/api/auth/userpass"
 	"github.com/spf13/pflag"
 	"github.com/tidwall/gjson"
-	authenticationv1 "k8s.io/api/authentication/v1"
+	authv1 "k8s.io/api/authentication/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
@@ -60,6 +60,7 @@ import (
 	vaultiamauth "github.com/external-secrets/external-secrets/pkg/provider/vault/iamauth"
 	"github.com/external-secrets/external-secrets/pkg/provider/vault/util"
 	"github.com/external-secrets/external-secrets/pkg/utils"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 var (
@@ -1088,7 +1089,7 @@ func (v *client) configureClientTLS(ctx context.Context, cfg *vault.Config) erro
 		if clientTLS.KeySecretRef.Key == "" {
 			clientTLS.KeySecretRef.Key = corev1.TLSPrivateKeyKey
 		}
-		clientKey, err := v.secretKeyRef(ctx, clientTLS.KeySecretRef)
+		clientKey, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, clientTLS.KeySecretRef)
 		if err != nil {
 			return err
 		}
@@ -1096,7 +1097,7 @@ func (v *client) configureClientTLS(ctx context.Context, cfg *vault.Config) erro
 		if clientTLS.CertSecretRef.Key == "" {
 			clientTLS.CertSecretRef.Key = corev1.TLSCertKey
 		}
-		clientCert, err := v.secretKeyRef(ctx, clientTLS.CertSecretRef)
+		clientCert, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, clientTLS.CertSecretRef)
 		if err != nil {
 			return err
 		}
@@ -1125,7 +1126,7 @@ func getCertFromSecret(v *client) ([]byte, error) {
 	}
 
 	ctx := context.Background()
-	res, err := v.secretKeyRef(ctx, &secretRef)
+	res, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, &secretRef)
 	if err != nil {
 		return nil, fmt.Errorf(errVaultCert, err)
 	}
@@ -1226,7 +1227,7 @@ func (v *client) setAuth(ctx context.Context, cfg *vault.Config) error {
 func setSecretKeyToken(ctx context.Context, v *client) (bool, error) {
 	tokenRef := v.store.Auth.TokenSecretRef
 	if tokenRef != nil {
-		token, err := v.secretKeyRef(ctx, tokenRef)
+		token, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, tokenRef)
 		if err != nil {
 			return true, err
 		}
@@ -1339,71 +1340,19 @@ func (v *client) secretKeyRefForServiceAccount(ctx context.Context, serviceAccou
 		return "", fmt.Errorf(errGetKubeSASecrets, ref.Name)
 	}
 	for _, tokenRef := range serviceAccount.Secrets {
-		retval, err := v.secretKeyRef(ctx, &esmeta.SecretKeySelector{
+		token, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, &esmeta.SecretKeySelector{
 			Name:      tokenRef.Name,
 			Namespace: &ref.Namespace,
 			Key:       "token",
 		})
-
 		if err != nil {
 			continue
 		}
-
-		return retval, nil
+		return token, nil
 	}
 	return "", fmt.Errorf(errGetKubeSANoToken, ref.Name)
 }
 
-func (v *client) secretKeyRef(ctx context.Context, secretRef *esmeta.SecretKeySelector) (string, error) {
-	secret := &corev1.Secret{}
-	ref := types.NamespacedName{
-		Namespace: v.namespace,
-		Name:      secretRef.Name,
-	}
-	if (v.storeKind == esv1beta1.ClusterSecretStoreKind) &&
-		(secretRef.Namespace != nil) {
-		ref.Namespace = *secretRef.Namespace
-	}
-	err := v.kube.Get(ctx, ref, secret)
-	if err != nil {
-		return "", fmt.Errorf(errGetKubeSecret, ref.Name, ref.Namespace, err)
-	}
-
-	keyBytes, ok := secret.Data[secretRef.Key]
-	if !ok {
-		return "", fmt.Errorf(errSecretKeyFmt, secretRef.Key)
-	}
-
-	value := string(keyBytes)
-	valueStr := strings.TrimSpace(value)
-	return valueStr, nil
-}
-
-func (v *client) serviceAccountToken(ctx context.Context, serviceAccountRef esmeta.ServiceAccountSelector, additionalAud []string, expirationSeconds int64) (string, error) {
-	audiences := serviceAccountRef.Audiences
-	if len(additionalAud) > 0 {
-		audiences = append(audiences, additionalAud...)
-	}
-	tokenRequest := &authenticationv1.TokenRequest{
-		ObjectMeta: metav1.ObjectMeta{
-			Namespace: v.namespace,
-		},
-		Spec: authenticationv1.TokenRequestSpec{
-			Audiences:         audiences,
-			ExpirationSeconds: &expirationSeconds,
-		},
-	}
-	if (v.storeKind == esv1beta1.ClusterSecretStoreKind) &&
-		(serviceAccountRef.Namespace != nil) {
-		tokenRequest.Namespace = *serviceAccountRef.Namespace
-	}
-	tokenResponse, err := v.corev1.ServiceAccounts(tokenRequest.Namespace).CreateToken(ctx, serviceAccountRef.Name, tokenRequest, metav1.CreateOptions{})
-	if err != nil {
-		return "", fmt.Errorf(errGetKubeSATokenRequest, serviceAccountRef.Name, err)
-	}
-	return tokenResponse.Status.Token, nil
-}
-
 // checkToken does a lookup and checks if the provided token exists.
 func checkToken(ctx context.Context, token util.Token) (bool, error) {
 	// https://www.vaultproject.io/api-docs/auth/token#lookup-a-token-self
@@ -1447,7 +1396,7 @@ func (v *client) requestTokenWithAppRoleRef(ctx context.Context, appRole *esv1be
 	if appRole.RoleID != "" { // use roleId from CRD, if configured
 		roleID = strings.TrimSpace(appRole.RoleID)
 	} else if appRole.RoleRef != nil { // use RoleID from Secret, if configured
-		roleID, err = v.secretKeyRef(ctx, appRole.RoleRef)
+		roleID, err = resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, appRole.RoleRef)
 		if err != nil {
 			return err
 		}
@@ -1455,7 +1404,7 @@ func (v *client) requestTokenWithAppRoleRef(ctx context.Context, appRole *esv1be
 		return fmt.Errorf(errInvalidAppRoleID)
 	}
 
-	secretID, err := v.secretKeyRef(ctx, &appRole.SecretRef)
+	secretID, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, &appRole.SecretRef)
 	if err != nil {
 		return err
 	}
@@ -1503,7 +1452,14 @@ func getJwtString(ctx context.Context, v *client, kubernetesAuth *esv1beta1.Vaul
 		// Kubernetes >=v1.24: fetch token via TokenRequest API
 		// note: this is a massive change from vault perspective: the `iss` claim will very likely change.
 		// Vault 1.9 deprecated issuer validation by default, and authentication with Vault clusters <1.9 will likely fail.
-		jwt, err = v.serviceAccountToken(ctx, *kubernetesAuth.ServiceAccountRef, nil, 600)
+		jwt, err = createServiceAccountToken(
+			ctx,
+			v.corev1,
+			v.storeKind,
+			v.namespace,
+			*kubernetesAuth.ServiceAccountRef,
+			nil,
+			600)
 		if err != nil {
 			return "", err
 		}
@@ -1514,7 +1470,7 @@ func getJwtString(ctx context.Context, v *client, kubernetesAuth *esv1beta1.Vaul
 			tokenRef = kubernetesAuth.SecretRef.DeepCopy()
 			tokenRef.Key = "token"
 		}
-		jwt, err := v.secretKeyRef(ctx, tokenRef)
+		jwt, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, tokenRef)
 		if err != nil {
 			return "", err
 		}
@@ -1536,8 +1492,7 @@ func getJwtString(ctx context.Context, v *client, kubernetesAuth *esv1beta1.Vaul
 
 func (v *client) requestTokenWithLdapAuth(ctx context.Context, ldapAuth *esv1beta1.VaultLdapAuth) error {
 	username := strings.TrimSpace(ldapAuth.Username)
-
-	password, err := v.secretKeyRef(ctx, &ldapAuth.SecretRef)
+	password, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, &ldapAuth.SecretRef)
 	if err != nil {
 		return err
 	}
@@ -1556,8 +1511,7 @@ func (v *client) requestTokenWithLdapAuth(ctx context.Context, ldapAuth *esv1bet
 
 func (v *client) requestTokenWithUserPassAuth(ctx context.Context, userPassAuth *esv1beta1.VaultUserPassAuth) error {
 	username := strings.TrimSpace(userPassAuth.Username)
-
-	password, err := v.secretKeyRef(ctx, &userPassAuth.SecretRef)
+	password, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, &userPassAuth.SecretRef)
 	if err != nil {
 		return err
 	}
@@ -1579,7 +1533,7 @@ func (v *client) requestTokenWithJwtAuth(ctx context.Context, jwtAuth *esv1beta1
 	var jwt string
 	var err error
 	if jwtAuth.SecretRef != nil {
-		jwt, err = v.secretKeyRef(ctx, jwtAuth.SecretRef)
+		jwt, err = resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, jwtAuth.SecretRef)
 	} else if k8sServiceAccountToken := jwtAuth.KubernetesServiceAccountToken; k8sServiceAccountToken != nil {
 		audiences := k8sServiceAccountToken.Audiences
 		if audiences == nil {
@@ -1590,7 +1544,14 @@ func (v *client) requestTokenWithJwtAuth(ctx context.Context, jwtAuth *esv1beta1
 			tmp := int64(600)
 			expirationSeconds = &tmp
 		}
-		jwt, err = v.serviceAccountToken(ctx, k8sServiceAccountToken.ServiceAccountRef, *audiences, *expirationSeconds)
+		jwt, err = createServiceAccountToken(
+			ctx,
+			v.corev1,
+			v.storeKind,
+			v.namespace,
+			k8sServiceAccountToken.ServiceAccountRef,
+			*audiences,
+			*expirationSeconds)
 	} else {
 		err = fmt.Errorf(errJwtNoTokenSource)
 	}
@@ -1618,12 +1579,12 @@ func (v *client) requestTokenWithJwtAuth(ctx context.Context, jwtAuth *esv1beta1
 }
 
 func (v *client) requestTokenWithCertAuth(ctx context.Context, certAuth *esv1beta1.VaultCertAuth, cfg *vault.Config) error {
-	clientKey, err := v.secretKeyRef(ctx, &certAuth.SecretRef)
+	clientKey, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, &certAuth.SecretRef)
 	if err != nil {
 		return err
 	}
 
-	clientCert, err := v.secretKeyRef(ctx, &certAuth.ClientCert)
+	clientCert, err := resolvers.SecretKeyRef(ctx, v.kube, v.storeKind, v.namespace, &certAuth.ClientCert)
 	if err != nil {
 		return err
 	}
@@ -1651,7 +1612,40 @@ func (v *client) requestTokenWithCertAuth(ctx context.Context, certAuth *esv1bet
 	return nil
 }
 
-func (v *client) requestTokenWithIamAuth(ctx context.Context, iamAuth *esv1beta1.VaultIamAuth, ick bool, k kclient.Client, n string, jwtProvider util.JwtProviderFactory, assumeRoler vaultiamauth.STSProvider) error {
+func createServiceAccountToken(
+	ctx context.Context,
+	corev1Client typedcorev1.CoreV1Interface,
+	storeKind string,
+	namespace string,
+	serviceAccountRef esmeta.ServiceAccountSelector,
+	additionalAud []string,
+	expirationSeconds int64) (string, error) {
+	audiences := serviceAccountRef.Audiences
+	if len(additionalAud) > 0 {
+		audiences = append(audiences, additionalAud...)
+	}
+	tokenRequest := &authv1.TokenRequest{
+		ObjectMeta: metav1.ObjectMeta{
+			Namespace: namespace,
+		},
+		Spec: authv1.TokenRequestSpec{
+			Audiences:         audiences,
+			ExpirationSeconds: &expirationSeconds,
+		},
+	}
+	if (storeKind == esv1beta1.ClusterSecretStoreKind) &&
+		(serviceAccountRef.Namespace != nil) {
+		tokenRequest.Namespace = *serviceAccountRef.Namespace
+	}
+	tokenResponse, err := corev1Client.ServiceAccounts(tokenRequest.Namespace).
+		CreateToken(ctx, serviceAccountRef.Name, tokenRequest, metav1.CreateOptions{})
+	if err != nil {
+		return "", fmt.Errorf(errGetKubeSATokenRequest, serviceAccountRef.Name, err)
+	}
+	return tokenResponse.Status.Token, nil
+}
+
+func (v *client) requestTokenWithIamAuth(ctx context.Context, iamAuth *esv1beta1.VaultIamAuth, isClusterKind bool, k kclient.Client, n string, jwtProvider util.JwtProviderFactory, assumeRoler vaultiamauth.STSProvider) error {
 	jwtAuth := iamAuth.JWTAuth
 	secretRefAuth := iamAuth.SecretRef
 	regionAWS := defaultAWSRegion
@@ -1665,13 +1659,13 @@ func (v *client) requestTokenWithIamAuth(ctx context.Context, iamAuth *esv1beta1
 	var creds *credentials.Credentials
 	var err error
 	if jwtAuth != nil { // use credentials from a sa explicitly defined and referenced. Highest preference is given to this method/configuration.
-		creds, err = vaultiamauth.CredsFromServiceAccount(ctx, *iamAuth, regionAWS, ick, k, n, jwtProvider)
+		creds, err = vaultiamauth.CredsFromServiceAccount(ctx, *iamAuth, regionAWS, isClusterKind, k, n, jwtProvider)
 		if err != nil {
 			return err
 		}
 	} else if secretRefAuth != nil { // if jwtAuth is not defined, check if secretRef is defined. Second preference.
 		logger.V(1).Info("using credentials from secretRef")
-		creds, err = vaultiamauth.CredsFromSecretRef(ctx, *iamAuth, ick, k, n)
+		creds, err = vaultiamauth.CredsFromSecretRef(ctx, *iamAuth, v.storeKind, k, n)
 		if err != nil {
 			return err
 		}

+ 1 - 1
pkg/provider/vault/vault_test.go

@@ -332,7 +332,7 @@ MIIFkTCCA3mgAwIBAgIUBEUg3m/WqAsWHG4Q/II3IePFfuowDQYJKoZIhvcNAQELBQAwWDELMAkGA1UE
 				kube: clientfake.NewClientBuilder().Build(),
 			},
 			want: want{
-				err: fmt.Errorf(errGetKubeSecret, "vault-secret", "default", errors.New("secrets \"vault-secret\" not found")),
+				err: fmt.Errorf(`cannot get Kubernetes secret "vault-secret": %w`, errors.New(`secrets "vault-secret" not found`)),
 			},
 		},
 		"SuccessfulVaultStoreWithCertAuth": {

+ 12 - 30
pkg/provider/webhook/webhook.go

@@ -25,7 +25,6 @@ import (
 	"net/http"
 	"net/url"
 	"strconv"
-	"strings"
 	tpl "text/template"
 	"time"
 
@@ -39,6 +38,7 @@ import (
 	"github.com/external-secrets/external-secrets/pkg/metrics"
 	"github.com/external-secrets/external-secrets/pkg/template/v2"
 	"github.com/external-secrets/external-secrets/pkg/utils"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 // https://github.com/external-secrets/external-secrets/issues/644
@@ -383,8 +383,9 @@ func (w *WebHook) getCACertPool(provider *esv1beta1.WebhookProvider) (*x509.Cert
 
 func (w *WebHook) getCertFromSecret(provider *esv1beta1.WebhookProvider) ([]byte, error) {
 	secretRef := esmeta.SecretKeySelector{
-		Name: provider.CAProvider.Name,
-		Key:  provider.CAProvider.Key,
+		Name:      provider.CAProvider.Name,
+		Namespace: &w.namespace,
+		Key:       provider.CAProvider.Key,
 	}
 
 	if provider.CAProvider.Namespace != nil {
@@ -392,37 +393,18 @@ func (w *WebHook) getCertFromSecret(provider *esv1beta1.WebhookProvider) ([]byte
 	}
 
 	ctx := context.Background()
-	res, err := w.secretKeyRef(ctx, &secretRef)
+	cert, err := resolvers.SecretKeyRef(
+		ctx,
+		w.kube,
+		w.storeKind,
+		w.namespace,
+		&secretRef,
+	)
 	if err != nil {
 		return nil, err
 	}
 
-	return []byte(res), nil
-}
-
-func (w *WebHook) secretKeyRef(ctx context.Context, secretRef *esmeta.SecretKeySelector) (string, error) {
-	secret := &corev1.Secret{}
-	ref := client.ObjectKey{
-		Namespace: w.namespace,
-		Name:      secretRef.Name,
-	}
-	if (w.storeKind == esv1beta1.ClusterSecretStoreKind) &&
-		(secretRef.Namespace != nil) {
-		ref.Namespace = *secretRef.Namespace
-	}
-	err := w.kube.Get(ctx, ref, secret)
-	if err != nil {
-		return "", err
-	}
-
-	keyBytes, ok := secret.Data[secretRef.Key]
-	if !ok {
-		return "", err
-	}
-
-	value := string(keyBytes)
-	valueStr := strings.TrimSpace(value)
-	return valueStr, nil
+	return []byte(cert), nil
 }
 
 func (w *WebHook) getCertFromConfigMap(provider *esv1beta1.WebhookProvider) ([]byte, error) {

+ 2 - 2
pkg/provider/yandex/certificatemanager/certificatemanager_test.go

@@ -80,7 +80,7 @@ func TestNewClient(t *testing.T) {
 	store.Spec.Provider.YandexCertificateManager.Auth.AuthorizedKey.Name = authorizedKeySecretName
 	store.Spec.Provider.YandexCertificateManager.Auth.AuthorizedKey.Key = authorizedKeySecretKey
 	secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
-	tassert.EqualError(t, err, "could not fetch AuthorizedKey secret: secrets \"authorizedKeySecretName\" not found")
+	tassert.EqualError(t, err, "cannot get Kubernetes secret \"authorizedKeySecretName\": secrets \"authorizedKeySecretName\" not found")
 	tassert.Nil(t, secretClient)
 
 	err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, newFakeAuthorizedKey()))
@@ -95,7 +95,7 @@ func TestNewClient(t *testing.T) {
 		},
 	}
 	secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
-	tassert.EqualError(t, err, "could not fetch CA certificate secret: secrets \"caCertificateSecretName\" not found")
+	tassert.EqualError(t, err, "cannot get Kubernetes secret \"caCertificateSecretName\": secrets \"caCertificateSecretName\" not found")
 	tassert.Nil(t, secretClient)
 
 	err = createK8sSecret(ctx, t, k8sClient, namespace, caCertificateSecretName, caCertificateSecretKey, []byte("it-is-not-a-certificate"))

+ 19 - 45
pkg/provider/yandex/common/provider.go

@@ -24,13 +24,12 @@ import (
 
 	"github.com/go-logr/logr"
 	"github.com/yandex-cloud/go-sdk/iamkey"
-	corev1 "k8s.io/api/core/v1"
-	"k8s.io/apimachinery/pkg/types"
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
 	clock2 "github.com/external-secrets/external-secrets/pkg/provider/yandex/common/clock"
+	"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
 )
 
 const maxSecretsClientLifetime = 5 * time.Minute // supposed SecretsClient lifetime is quite short
@@ -115,61 +114,36 @@ func (p *YandexCloudProvider) NewClient(ctx context.Context, store esv1beta1.Gen
 		return nil, err
 	}
 
-	objectKey := types.NamespacedName{
-		Name:      input.AuthorizedKey.Name,
-		Namespace: namespace,
-	}
-
-	// only ClusterStore is allowed to set namespace (and then it's required)
-	if store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind {
-		if input.AuthorizedKey.Namespace == nil {
-			return nil, fmt.Errorf("invalid ClusterSecretStore: missing AuthorizedKey Namespace")
-		}
-		objectKey.Namespace = *input.AuthorizedKey.Namespace
-	}
-
-	authorizedKeySecret := &corev1.Secret{}
-	err = kube.Get(ctx, objectKey, authorizedKeySecret)
+	key, err := resolvers.SecretKeyRef(
+		ctx,
+		kube,
+		store.GetKind(),
+		namespace,
+		&input.AuthorizedKey,
+	)
 	if err != nil {
-		return nil, fmt.Errorf("could not fetch AuthorizedKey secret: %w", err)
-	}
-
-	authorizedKeySecretData := authorizedKeySecret.Data[input.AuthorizedKey.Key]
-	if (authorizedKeySecretData == nil) || (len(authorizedKeySecretData) == 0) {
-		return nil, fmt.Errorf("missing AuthorizedKey")
+		return nil, err
 	}
 
 	var authorizedKey iamkey.Key
-	err = json.Unmarshal(authorizedKeySecretData, &authorizedKey)
+	err = json.Unmarshal([]byte(key), &authorizedKey)
 	if err != nil {
 		return nil, fmt.Errorf("unable to unmarshal authorized key: %w", err)
 	}
 
 	var caCertificateData []byte
-
 	if input.CACertificate != nil {
-		certObjectKey := types.NamespacedName{
-			Name:      input.CACertificate.Name,
-			Namespace: namespace,
-		}
-
-		if store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind {
-			if input.CACertificate.Namespace == nil {
-				return nil, fmt.Errorf("invalid ClusterSecretStore: missing CA certificate Namespace")
-			}
-			certObjectKey.Namespace = *input.CACertificate.Namespace
-		}
-
-		caCertificateSecret := &corev1.Secret{}
-		err := kube.Get(ctx, certObjectKey, caCertificateSecret)
+		caCert, err := resolvers.SecretKeyRef(
+			ctx,
+			kube,
+			store.GetKind(),
+			namespace,
+			input.CACertificate,
+		)
 		if err != nil {
-			return nil, fmt.Errorf("could not fetch CA certificate secret: %w", err)
-		}
-
-		caCertificateData = caCertificateSecret.Data[input.CACertificate.Key]
-		if (caCertificateData == nil) || (len(caCertificateData) == 0) {
-			return nil, fmt.Errorf("missing CA Certificate")
+			return nil, err
 		}
+		caCertificateData = []byte(caCert)
 	}
 
 	secretGetter, err := p.getOrCreateSecretGetter(ctx, input.APIEndpoint, &authorizedKey, caCertificateData)

+ 2 - 2
pkg/provider/yandex/lockbox/lockbox_test.go

@@ -80,7 +80,7 @@ func TestNewClient(t *testing.T) {
 	store.Spec.Provider.YandexLockbox.Auth.AuthorizedKey.Name = authorizedKeySecretName
 	store.Spec.Provider.YandexLockbox.Auth.AuthorizedKey.Key = authorizedKeySecretKey
 	secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
-	tassert.EqualError(t, err, "could not fetch AuthorizedKey secret: secrets \"authorizedKeySecretName\" not found")
+	tassert.EqualError(t, err, "cannot get Kubernetes secret \"authorizedKeySecretName\": secrets \"authorizedKeySecretName\" not found")
 	tassert.Nil(t, secretClient)
 
 	err = createK8sSecret(ctx, t, k8sClient, namespace, authorizedKeySecretName, authorizedKeySecretKey, toJSON(t, newFakeAuthorizedKey()))
@@ -95,7 +95,7 @@ func TestNewClient(t *testing.T) {
 		},
 	}
 	secretClient, err = provider.NewClient(context.Background(), store, k8sClient, namespace)
-	tassert.EqualError(t, err, "could not fetch CA certificate secret: secrets \"caCertificateSecretName\" not found")
+	tassert.EqualError(t, err, "cannot get Kubernetes secret \"caCertificateSecretName\": secrets \"caCertificateSecretName\" not found")
 	tassert.Nil(t, secretClient)
 
 	err = createK8sSecret(ctx, t, k8sClient, namespace, caCertificateSecretName, caCertificateSecretKey, []byte("it-is-not-a-certificate"))

+ 71 - 0
pkg/utils/resolvers/secret_ref.go

@@ -0,0 +1,71 @@
+/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package resolvers
+
+import (
+	"context"
+	"fmt"
+
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/types"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+
+	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
+	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
+)
+
+const (
+
+	// This is used to determine if a store is cluster-scoped or not.
+	// The EmptyStoreKind is not cluster-scoped, hence resources
+	// cannot be resolved across namespaces.
+	// TODO: when we implement cluster-scoped generators
+	// we can remove this and replace it with a interface.
+	EmptyStoreKind = "EmptyStoreKind"
+
+	errGetKubeSecret         = "cannot get Kubernetes secret %q: %w"
+	errSecretKeyFmt          = "cannot find secret data for key: %q"
+	errGetKubeSATokenRequest = "cannot request Kubernetes service account token for service account %q: %w"
+)
+
+// SecretKeyRef resolves a metav1.SecretKeySelector and returns the value of the secret it points to.
+// A user must pass the namespace of the originating ExternalSecret, as this may differ
+// from the namespace defined in the SecretKeySelector.
+// This func ensures that only a ClusterSecretStore is able to request secrets across namespaces.
+func SecretKeyRef(
+	ctx context.Context,
+	c client.Client,
+	storeKind string,
+	esNamespace string,
+	ref *esmeta.SecretKeySelector) (string, error) {
+	key := types.NamespacedName{
+		Namespace: esNamespace,
+		Name:      ref.Name,
+	}
+	if (storeKind == esv1beta1.ClusterSecretStoreKind) &&
+		(ref.Namespace != nil) {
+		key.Namespace = *ref.Namespace
+	}
+	secret := &corev1.Secret{}
+	err := c.Get(ctx, key, secret)
+	if err != nil {
+		return "", fmt.Errorf(errGetKubeSecret, ref.Name, err)
+	}
+	val, ok := secret.Data[ref.Key]
+	if !ok {
+		return "", fmt.Errorf(errSecretKeyFmt, ref.Key)
+	}
+	return string(val), nil
+}

+ 129 - 0
pkg/utils/resolvers/secret_ref_test.go

@@ -0,0 +1,129 @@
+/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package resolvers
+
+import (
+	"context"
+	"errors"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/client-go/kubernetes/scheme"
+	"k8s.io/utils/ptr"
+	"sigs.k8s.io/controller-runtime/pkg/client/fake"
+
+	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
+)
+
+func TestResolveSecretKeyRef(t *testing.T) {
+	ctx := context.TODO()
+	c := fake.NewClientBuilder().WithScheme(scheme.Scheme).Build()
+	testNamespace := "test-namespace"
+	testSecret := "test-secret"
+	testKey := "test-key"
+	testValue := "test-value"
+	secret := &corev1.Secret{
+		ObjectMeta: metav1.ObjectMeta{
+			Namespace: testNamespace,
+			Name:      testSecret,
+		},
+		Data: map[string][]byte{
+			testKey: []byte(testValue),
+		},
+	}
+	err := c.Create(ctx, secret)
+	require.NoError(t, err)
+
+	testCases := []struct {
+		name      string
+		namespace string
+		storeKind string
+		selector  *esmeta.SecretKeySelector
+		expected  string
+		err       error
+	}{
+		{
+			name:      "namespaced secret store can access secret in same namespace",
+			namespace: testNamespace,
+			storeKind: "SecretStore",
+			selector: &esmeta.SecretKeySelector{
+				Name:      testSecret,
+				Namespace: ptr.To(testNamespace),
+				Key:       testKey,
+			},
+			expected: testValue,
+			err:      nil,
+		},
+		{
+			name:      "omitting namespace in secret store defaults to same namespace",
+			namespace: testNamespace,
+			storeKind: "SecretStore",
+			selector: &esmeta.SecretKeySelector{
+				Name: testSecret,
+				Key:  testKey,
+			},
+			expected: testValue,
+			err:      nil,
+		},
+		{
+			name:      "namespaced secret store can not access secret in different namespace",
+			namespace: "other-namespace",
+			storeKind: "SecretStore",
+			selector: &esmeta.SecretKeySelector{
+				Name:      testSecret,
+				Namespace: ptr.To(testNamespace),
+				Key:       testKey,
+			},
+			err: errors.New(`cannot get Kubernetes secret "test-secret": secrets "test-secret" not found`),
+		},
+		{
+			name:      "cluster secret store may access all namespaces",
+			storeKind: "ClusterSecretStore",
+			selector: &esmeta.SecretKeySelector{
+				Name:      testSecret,
+				Namespace: ptr.To(testNamespace),
+				Key:       testKey,
+			},
+			expected: testValue,
+			err:      nil,
+		},
+		{
+			name:      "key not found in secret",
+			namespace: testNamespace,
+			storeKind: "SecretStore",
+			selector: &esmeta.SecretKeySelector{
+				Name:      testSecret,
+				Namespace: ptr.To(testNamespace),
+				Key:       "xxxxxxxx",
+			},
+			expected: "",
+			err:      errors.New(`cannot find secret data for key: "xxxxxxxx"`),
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			resolvedValue, err := SecretKeyRef(ctx, c, tc.storeKind, tc.namespace, tc.selector)
+			if tc.err != nil {
+				assert.EqualError(t, err, tc.err.Error())
+			} else {
+				require.NoError(t, err)
+			}
+			assert.Equal(t, tc.expected, resolvedValue)
+		})
+	}
+}