Browse Source

Changes to PushSecret Definition.
Adds tests, adds labelSelector

Signed-off-by: Gustavo <gusfcarvalho@gmail.com>

Gustavo 3 years ago
parent
commit
6758c92979

+ 20 - 8
apis/externalsecrets/v1alpha1/pushsecret_types.go

@@ -25,9 +25,12 @@ const (
 )
 )
 
 
 type PushSecretStoreRef struct {
 type PushSecretStoreRef struct {
-	// Name of the SecretStore resource
+	// Optionally, sync to the SecretStore of the given name
+	// +optional
 	Name string `json:"name"`
 	Name string `json:"name"`
-
+	// Optionally, sync to secret stores with label selector
+	// +optional
+	LabelSelector *metav1.LabelSelector `json:"labelSelector"`
 	// Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
 	// Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
 	// Defaults to `SecretStore`
 	// Defaults to `SecretStore`
 	// +optional
 	// +optional
@@ -36,34 +39,43 @@ type PushSecretStoreRef struct {
 
 
 // PushSecretSpec configures the behavior of the PushSecret.
 // PushSecretSpec configures the behavior of the PushSecret.
 type PushSecretSpec struct {
 type PushSecretSpec struct {
+	// The Interval to which External Secrets will try to push a secret definition
 	RefreshInterval *metav1.Duration     `json:"refreshInterval,omitempty"`
 	RefreshInterval *metav1.Duration     `json:"refreshInterval,omitempty"`
 	SecretStoreRefs []PushSecretStoreRef `json:"secretStoreRefs"`
 	SecretStoreRefs []PushSecretStoreRef `json:"secretStoreRefs"`
-	Selector        PushSecretSelector   `json:"selector"`
-	Data            []PushSecretData     `json:"data,omitempty"`
+	// The Secret Selector (k8s source) for the Push Secret
+	Selector PushSecretSelector `json:"selector"`
+	// Secret Data that should be pushed to providers
+	Data []PushSecretData `json:"data,omitempty"`
 }
 }
 
 
 type PushSecretSecret struct {
 type PushSecretSecret struct {
+	// Name of the Secret. The Secret must exist in the same namespace as the PushSecret manifest.
 	Name string `json:"name"`
 	Name string `json:"name"`
 }
 }
 
 
 type PushSecretSelector struct {
 type PushSecretSelector struct {
+	// Select a Secret to Push.
 	Secret PushSecretSecret `json:"secret"`
 	Secret PushSecretSecret `json:"secret"`
 }
 }
 
 
-type PushSecretRemoteRefs struct {
+type PushSecretRemoteRef struct {
+	// Name of the resulting provider secret.
 	RemoteKey string `json:"remoteKey"`
 	RemoteKey string `json:"remoteKey"`
 }
 }
 
 
-func (r PushSecretRemoteRefs) GetRemoteKey() string {
+func (r PushSecretRemoteRef) GetRemoteKey() string {
 	return r.RemoteKey
 	return r.RemoteKey
 }
 }
 
 
 type PushSecretMatch struct {
 type PushSecretMatch struct {
-	SecretKey  string                 `json:"secretKey"`
-	RemoteRefs []PushSecretRemoteRefs `json:"remoteRefs"`
+	// Secret Key to be pushed
+	SecretKey string `json:"secretKey"`
+	// Remote Refs to push to providers.
+	RemoteRef PushSecretRemoteRef `json:"remoteRef"`
 }
 }
 
 
 type PushSecretData struct {
 type PushSecretData struct {
+	// Match a given Secret Key to be pushed to the provider.
 	Match PushSecretMatch `json:"match"`
 	Match PushSecretMatch `json:"match"`
 }
 }
 
 

+ 15 - 14
apis/externalsecrets/v1alpha1/zz_generated.deepcopy.go

@@ -1024,7 +1024,7 @@ func (in *PushSecret) DeepCopyObject() runtime.Object {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *PushSecretData) DeepCopyInto(out *PushSecretData) {
 func (in *PushSecretData) DeepCopyInto(out *PushSecretData) {
 	*out = *in
 	*out = *in
-	in.Match.DeepCopyInto(&out.Match)
+	out.Match = in.Match
 }
 }
 
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PushSecretData.
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PushSecretData.
@@ -1072,11 +1072,7 @@ func (in *PushSecretList) DeepCopyObject() runtime.Object {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *PushSecretMatch) DeepCopyInto(out *PushSecretMatch) {
 func (in *PushSecretMatch) DeepCopyInto(out *PushSecretMatch) {
 	*out = *in
 	*out = *in
-	if in.RemoteRefs != nil {
-		in, out := &in.RemoteRefs, &out.RemoteRefs
-		*out = make([]PushSecretRemoteRefs, len(*in))
-		copy(*out, *in)
-	}
+	out.RemoteRef = in.RemoteRef
 }
 }
 
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PushSecretMatch.
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PushSecretMatch.
@@ -1090,16 +1086,16 @@ func (in *PushSecretMatch) DeepCopy() *PushSecretMatch {
 }
 }
 
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *PushSecretRemoteRefs) DeepCopyInto(out *PushSecretRemoteRefs) {
+func (in *PushSecretRemoteRef) DeepCopyInto(out *PushSecretRemoteRef) {
 	*out = *in
 	*out = *in
 }
 }
 
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PushSecretRemoteRefs.
-func (in *PushSecretRemoteRefs) DeepCopy() *PushSecretRemoteRefs {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PushSecretRemoteRef.
+func (in *PushSecretRemoteRef) DeepCopy() *PushSecretRemoteRef {
 	if in == nil {
 	if in == nil {
 		return nil
 		return nil
 	}
 	}
-	out := new(PushSecretRemoteRefs)
+	out := new(PushSecretRemoteRef)
 	in.DeepCopyInto(out)
 	in.DeepCopyInto(out)
 	return out
 	return out
 }
 }
@@ -1146,15 +1142,15 @@ func (in *PushSecretSpec) DeepCopyInto(out *PushSecretSpec) {
 	if in.SecretStoreRefs != nil {
 	if in.SecretStoreRefs != nil {
 		in, out := &in.SecretStoreRefs, &out.SecretStoreRefs
 		in, out := &in.SecretStoreRefs, &out.SecretStoreRefs
 		*out = make([]PushSecretStoreRef, len(*in))
 		*out = make([]PushSecretStoreRef, len(*in))
-		copy(*out, *in)
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
 	}
 	}
 	out.Selector = in.Selector
 	out.Selector = in.Selector
 	if in.Data != nil {
 	if in.Data != nil {
 		in, out := &in.Data, &out.Data
 		in, out := &in.Data, &out.Data
 		*out = make([]PushSecretData, len(*in))
 		*out = make([]PushSecretData, len(*in))
-		for i := range *in {
-			(*in)[i].DeepCopyInto(&(*out)[i])
-		}
+		copy(*out, *in)
 	}
 	}
 }
 }
 
 
@@ -1210,6 +1206,11 @@ func (in *PushSecretStatusCondition) DeepCopy() *PushSecretStatusCondition {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *PushSecretStoreRef) DeepCopyInto(out *PushSecretStoreRef) {
 func (in *PushSecretStoreRef) DeepCopyInto(out *PushSecretStoreRef) {
 	*out = *in
 	*out = *in
+	if in.LabelSelector != nil {
+		in, out := &in.LabelSelector, &out.LabelSelector
+		*out = new(v1.LabelSelector)
+		(*in).DeepCopyInto(*out)
+	}
 }
 }
 
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PushSecretStoreRef.
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PushSecretStoreRef.

+ 66 - 13
config/crds/bases/external-secrets.io_pushsecrets.yaml

@@ -43,23 +43,26 @@ spec:
             description: PushSecretSpec configures the behavior of the PushSecret.
             description: PushSecretSpec configures the behavior of the PushSecret.
             properties:
             properties:
               data:
               data:
+                description: Secret Data that should be pushed to providers
                 items:
                 items:
                   properties:
                   properties:
                     match:
                     match:
+                      description: Match a given Secret Key to be pushed to the provider.
                       properties:
                       properties:
-                        remoteRefs:
-                          items:
-                            properties:
-                              remoteKey:
-                                type: string
-                            required:
-                            - remoteKey
-                            type: object
-                          type: array
+                        remoteRef:
+                          description: Remote Refs to push to providers.
+                          properties:
+                            remoteKey:
+                              description: Name of the resulting provider secret.
+                              type: string
+                          required:
+                          - remoteKey
+                          type: object
                         secretKey:
                         secretKey:
+                          description: Secret Key to be pushed
                           type: string
                           type: string
                       required:
                       required:
-                      - remoteRefs
+                      - remoteRef
                       - secretKey
                       - secretKey
                       type: object
                       type: object
                   required:
                   required:
@@ -67,6 +70,8 @@ spec:
                   type: object
                   type: object
                 type: array
                 type: array
               refreshInterval:
               refreshInterval:
+                description: The Interval to which External Secrets will try to push
+                  a secret definition
                 type: string
                 type: string
               secretStoreRefs:
               secretStoreRefs:
                 items:
                 items:
@@ -75,18 +80,66 @@ spec:
                       description: Kind of the SecretStore resource (SecretStore or
                       description: Kind of the SecretStore resource (SecretStore or
                         ClusterSecretStore) Defaults to `SecretStore`
                         ClusterSecretStore) Defaults to `SecretStore`
                       type: string
                       type: string
+                    labelSelector:
+                      description: Optionally, sync to secret stores with label selector
+                      properties:
+                        matchExpressions:
+                          description: matchExpressions is a list of label selector
+                            requirements. The requirements are ANDed.
+                          items:
+                            description: A label selector requirement is a selector
+                              that contains values, a key, and an operator that relates
+                              the key and values.
+                            properties:
+                              key:
+                                description: key is the label key that the selector
+                                  applies to.
+                                type: string
+                              operator:
+                                description: operator represents a key's relationship
+                                  to a set of values. Valid operators are In, NotIn,
+                                  Exists and DoesNotExist.
+                                type: string
+                              values:
+                                description: values is an array of string values.
+                                  If the operator is In or NotIn, the values array
+                                  must be non-empty. If the operator is Exists or
+                                  DoesNotExist, the values array must be empty. This
+                                  array is replaced during a strategic merge patch.
+                                items:
+                                  type: string
+                                type: array
+                            required:
+                            - key
+                            - operator
+                            type: object
+                          type: array
+                        matchLabels:
+                          additionalProperties:
+                            type: string
+                          description: matchLabels is a map of {key,value} pairs.
+                            A single {key,value} in the matchLabels map is equivalent
+                            to an element of matchExpressions, whose key field is
+                            "key", the operator is "In", and the values array contains
+                            only "value". The requirements are ANDed.
+                          type: object
+                      type: object
+                      x-kubernetes-map-type: atomic
                     name:
                     name:
-                      description: Name of the SecretStore resource
+                      description: Optionally, sync to the SecretStore of the given
+                        name
                       type: string
                       type: string
-                  required:
-                  - name
                   type: object
                   type: object
                 type: array
                 type: array
               selector:
               selector:
+                description: The Secret Selector (k8s source) for the Push Secret
                 properties:
                 properties:
                   secret:
                   secret:
+                    description: Select a Secret to Push.
                     properties:
                     properties:
                       name:
                       name:
+                        description: Name of the Secret. The Secret must exist in
+                          the same namespace as the PushSecret manifest.
                         type: string
                         type: string
                     required:
                     required:
                     - name
                     - name

+ 49 - 13
deploy/crds/bundle.yaml

@@ -3294,23 +3294,26 @@ spec:
               description: PushSecretSpec configures the behavior of the PushSecret.
               description: PushSecretSpec configures the behavior of the PushSecret.
               properties:
               properties:
                 data:
                 data:
+                  description: Secret Data that should be pushed to providers
                   items:
                   items:
                     properties:
                     properties:
                       match:
                       match:
+                        description: Match a given Secret Key to be pushed to the provider.
                         properties:
                         properties:
-                          remoteRefs:
-                            items:
-                              properties:
-                                remoteKey:
-                                  type: string
-                              required:
-                                - remoteKey
-                              type: object
-                            type: array
+                          remoteRef:
+                            description: Remote Refs to push to providers.
+                            properties:
+                              remoteKey:
+                                description: Name of the resulting provider secret.
+                                type: string
+                            required:
+                              - remoteKey
+                            type: object
                           secretKey:
                           secretKey:
+                            description: Secret Key to be pushed
                             type: string
                             type: string
                         required:
                         required:
-                          - remoteRefs
+                          - remoteRef
                           - secretKey
                           - secretKey
                         type: object
                         type: object
                     required:
                     required:
@@ -3318,6 +3321,7 @@ spec:
                     type: object
                     type: object
                   type: array
                   type: array
                 refreshInterval:
                 refreshInterval:
+                  description: The Interval to which External Secrets will try to push a secret definition
                   type: string
                   type: string
                 secretStoreRefs:
                 secretStoreRefs:
                   items:
                   items:
@@ -3325,18 +3329,50 @@ spec:
                       kind:
                       kind:
                         description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore) Defaults to `SecretStore`
                         description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore) Defaults to `SecretStore`
                         type: string
                         type: string
+                      labelSelector:
+                        description: Optionally, sync to secret stores with label selector
+                        properties:
+                          matchExpressions:
+                            description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
+                            items:
+                              description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
+                              properties:
+                                key:
+                                  description: key is the label key that the selector applies to.
+                                  type: string
+                                operator:
+                                  description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
+                                  type: string
+                                values:
+                                  description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
+                                  items:
+                                    type: string
+                                  type: array
+                              required:
+                                - key
+                                - operator
+                              type: object
+                            type: array
+                          matchLabels:
+                            additionalProperties:
+                              type: string
+                            description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
+                            type: object
+                        type: object
+                        x-kubernetes-map-type: atomic
                       name:
                       name:
-                        description: Name of the SecretStore resource
+                        description: Optionally, sync to the SecretStore of the given name
                         type: string
                         type: string
-                    required:
-                      - name
                     type: object
                     type: object
                   type: array
                   type: array
                 selector:
                 selector:
+                  description: The Secret Selector (k8s source) for the Push Secret
                   properties:
                   properties:
                     secret:
                     secret:
+                      description: Select a Secret to Push.
                       properties:
                       properties:
                         name:
                         name:
+                          description: Name of the Secret. The Secret must exist in the same namespace as the PushSecret manifest.
                           type: string
                           type: string
                       required:
                       required:
                         - name
                         - name

+ 1 - 1
design/002-pushsecret.md

@@ -24,7 +24,7 @@ The Secret Sink is a feature to allow Secrets from Kubernetes to be saved back i
 Secret Sink allows some inCluster generated secrets to also be available on a given secret provider. It also allows multiple Providers having the same secret (which means a way to perform failover in case a given secret provider is on downtime or compromised for whatever the reason).
 Secret Sink allows some inCluster generated secrets to also be available on a given secret provider. It also allows multiple Providers having the same secret (which means a way to perform failover in case a given secret provider is on downtime or compromised for whatever the reason).
 
 
 ### Goals
 ### Goals
-- CRD Design for the PushSecret
+- CRD Design for the SecretSink
 - Define the need for a SinkStore
 - Define the need for a SinkStore
 -
 -
 ### Non-Goals
 ### Non-Goals

+ 47 - 23
pkg/controllers/pushsecret/pushsecret_controller.go

@@ -93,7 +93,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
 		r.recorder.Event(&ps, v1.EventTypeWarning, esapi.ReasonErrored, err.Error())
 		r.recorder.Event(&ps, v1.EventTypeWarning, esapi.ReasonErrored, err.Error())
 		return ctrl.Result{}, err
 		return ctrl.Result{}, err
 	}
 	}
-	err = r.SetSecretToProviders(ctx, secretStores, ps, secret)
+	err = r.PushSecretToProviders(ctx, secretStores, ps, secret)
 	if err != nil {
 	if err != nil {
 		msg := fmt.Sprintf(errFailedSetSecret, err)
 		msg := fmt.Sprintf(errFailedSetSecret, err)
 		cond := NewPushSecretCondition(esapi.PushSecretReady, v1.ConditionFalse, esapi.ReasonErrored, msg)
 		cond := NewPushSecretCondition(esapi.PushSecretReady, v1.ConditionFalse, esapi.ReasonErrored, msg)
@@ -109,7 +109,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
 	return ctrl.Result{RequeueAfter: refreshInt}, nil
 	return ctrl.Result{RequeueAfter: refreshInt}, nil
 }
 }
 
 
-func (r *Reconciler) SetSecretToProviders(ctx context.Context, stores []v1beta1.GenericStore, ps esapi.PushSecret, secret *v1.Secret) error {
+func (r *Reconciler) PushSecretToProviders(ctx context.Context, stores []v1beta1.GenericStore, ps esapi.PushSecret, secret *v1.Secret) error {
 	for _, store := range stores {
 	for _, store := range stores {
 		provider, err := v1beta1.GetProvider(store)
 		provider, err := v1beta1.GetProvider(store)
 		if err != nil {
 		if err != nil {
@@ -130,11 +130,9 @@ func (r *Reconciler) SetSecretToProviders(ctx context.Context, stores []v1beta1.
 			if !ok {
 			if !ok {
 				return fmt.Errorf("secret key %v does not exist", ref.Match.SecretKey)
 				return fmt.Errorf("secret key %v does not exist", ref.Match.SecretKey)
 			}
 			}
-			for _, rK := range ref.Match.RemoteRefs {
-				err := client.SetSecret(ctx, secretValue, rK)
-				if err != nil {
-					return fmt.Errorf(errSetSecretFailed, ref.Match.SecretKey, store.GetName(), err)
-				}
+			err := client.SetSecret(ctx, secretValue, ref.Match.RemoteRef)
+			if err != nil {
+				return fmt.Errorf(errSetSecretFailed, ref.Match.SecretKey, store.GetName(), err)
 			}
 			}
 		}
 		}
 	}
 	}
@@ -154,26 +152,52 @@ func (r *Reconciler) GetSecret(ctx context.Context, ps esapi.PushSecret) (*v1.Se
 func (r *Reconciler) GetSecretStores(ctx context.Context, ps esapi.PushSecret) ([]v1beta1.GenericStore, error) {
 func (r *Reconciler) GetSecretStores(ctx context.Context, ps esapi.PushSecret) ([]v1beta1.GenericStore, error) {
 	stores := make([]v1beta1.GenericStore, 0)
 	stores := make([]v1beta1.GenericStore, 0)
 	for _, refStore := range ps.Spec.SecretStoreRefs {
 	for _, refStore := range ps.Spec.SecretStoreRefs {
-		ref := types.NamespacedName{
-			Name: refStore.Name,
-		}
-
-		if refStore.Kind == v1beta1.ClusterSecretStoreKind {
-			var store v1beta1.ClusterSecretStore
-			err := r.Get(ctx, ref, &store)
+		if refStore.LabelSelector != nil {
+			labelSelector, err := metav1.LabelSelectorAsSelector(refStore.LabelSelector)
 			if err != nil {
 			if err != nil {
-				return nil, fmt.Errorf(errGetClusterSecretStore, ref.Name, err)
+				return nil, fmt.Errorf("could not convert labels: %w", err)
 			}
 			}
-			stores = append(stores, &store)
-		} else {
-			ref.Namespace = ps.Namespace
+			if refStore.Kind == v1beta1.ClusterSecretStoreKind {
+				clusterSecretStoreList := v1beta1.ClusterSecretStoreList{}
+				err = r.List(ctx, &clusterSecretStoreList, &client.ListOptions{LabelSelector: labelSelector})
+				if err != nil {
+					return nil, fmt.Errorf("could not list cluster Secret Stores: %w", err)
+				}
+				for i := range clusterSecretStoreList.Items {
+					stores = append(stores, &clusterSecretStoreList.Items[i])
+				}
+			} else {
+				secretStoreList := v1beta1.SecretStoreList{}
+				err = r.List(ctx, &secretStoreList, &client.ListOptions{LabelSelector: labelSelector})
+				if err != nil {
+					return nil, fmt.Errorf("could not list Secret Stores: %w", err)
+				}
+				for i := range secretStoreList.Items {
+					stores = append(stores, &secretStoreList.Items[i])
+				}
+			}
+		}
+		if refStore.Name != "" {
+			ref := types.NamespacedName{
+				Name: refStore.Name,
+			}
+			if refStore.Kind == v1beta1.ClusterSecretStoreKind {
+				var store v1beta1.ClusterSecretStore
+				err := r.Get(ctx, ref, &store)
+				if err != nil {
+					return nil, fmt.Errorf(errGetClusterSecretStore, ref.Name, err)
+				}
+				stores = append(stores, &store)
+			} else {
+				ref.Namespace = ps.Namespace
 
 
-			var store v1beta1.SecretStore
-			err := r.Get(ctx, ref, &store)
-			if err != nil {
-				return nil, fmt.Errorf(errGetSecretStore, ref.Name, err)
+				var store v1beta1.SecretStore
+				err := r.Get(ctx, ref, &store)
+				if err != nil {
+					return nil, fmt.Errorf(errGetSecretStore, ref.Name, err)
+				}
+				stores = append(stores, &store)
 			}
 			}
-			stores = append(stores, &store)
 		}
 		}
 	}
 	}
 	return stores, nil
 	return stores, nil

+ 142 - 6
pkg/controllers/pushsecret/pushsecret_controller_test.go

@@ -111,6 +111,11 @@ var _ = Describe("ExternalSecret controller", func() {
 				Namespace: PushSecretNamespace,
 				Namespace: PushSecretNamespace,
 			},
 			},
 		})
 		})
+		k8sClient.Delete(context.Background(), &v1beta1.ClusterSecretStore{
+			ObjectMeta: metav1.ObjectMeta{
+				Name: PushSecretStore,
+			},
+		})
 		k8sClient.Delete(context.Background(), &v1.Secret{
 		k8sClient.Delete(context.Background(), &v1.Secret{
 			ObjectMeta: metav1.ObjectMeta{
 			ObjectMeta: metav1.ObjectMeta{
 				Name:      SecretName,
 				Name:      SecretName,
@@ -142,10 +147,8 @@ var _ = Describe("ExternalSecret controller", func() {
 						{
 						{
 							Match: v1alpha1.PushSecretMatch{
 							Match: v1alpha1.PushSecretMatch{
 								SecretKey: "key",
 								SecretKey: "key",
-								RemoteRefs: []v1alpha1.PushSecretRemoteRefs{
-									{
-										RemoteKey: "path/to/key",
-									},
+								RemoteRef: v1alpha1.PushSecretRemoteRef{
+									RemoteKey: "path/to/key",
 								},
 								},
 							},
 							},
 						},
 						},
@@ -184,7 +187,73 @@ var _ = Describe("ExternalSecret controller", func() {
 		}
 		}
 		tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
 		tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
 			secretValue := secret.Data["key"]
 			secretValue := secret.Data["key"]
-			providerValue := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRefs[0].RemoteKey].Value
+			providerValue := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
+			expected := v1alpha1.PushSecretStatusCondition{
+				Type:    v1alpha1.PushSecretReady,
+				Status:  v1.ConditionTrue,
+				Reason:  v1alpha1.ReasonSynced,
+				Message: "PushSecret synced successfully",
+			}
+			return bytes.Equal(secretValue, providerValue) && checkCondition(ps.Status, expected)
+		}
+	}
+	// if target Secret name is not specified it should use the ExternalSecret name.
+	syncMatchingLabels := func(tc *testCase) {
+		fakeProvider.SetSecretFn = func() error {
+			return nil
+		}
+		tc.pushsecret = &v1alpha1.PushSecret{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      PushSecretName,
+				Namespace: PushSecretNamespace,
+			},
+			Spec: v1alpha1.PushSecretSpec{
+				SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
+					{
+						LabelSelector: &metav1.LabelSelector{
+							MatchLabels: map[string]string{
+								"foo": "bar",
+							},
+						},
+						Kind: "SecretStore",
+					},
+				},
+				Selector: v1alpha1.PushSecretSelector{
+					Secret: v1alpha1.PushSecretSecret{
+						Name: SecretName,
+					},
+				},
+				Data: []v1alpha1.PushSecretData{
+					{
+						Match: v1alpha1.PushSecretMatch{
+							SecretKey: "key",
+							RemoteRef: v1alpha1.PushSecretRemoteRef{
+								RemoteKey: "path/to/key",
+							},
+						},
+					},
+				},
+			},
+		}
+		tc.store = &v1beta1.SecretStore{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      PushSecretStore,
+				Namespace: PushSecretNamespace,
+				Labels: map[string]string{
+					"foo": "bar",
+				},
+			},
+			Spec: v1beta1.SecretStoreSpec{
+				Provider: &v1beta1.SecretStoreProvider{
+					Fake: &v1beta1.FakeProvider{
+						Data: []v1beta1.FakeProviderData{},
+					},
+				},
+			},
+		}
+		tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
+			secretValue := secret.Data["key"]
+			providerValue := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
 			expected := v1alpha1.PushSecretStatusCondition{
 			expected := v1alpha1.PushSecretStatusCondition{
 				Type:    v1alpha1.PushSecretReady,
 				Type:    v1alpha1.PushSecretReady,
 				Status:  v1.ConditionTrue,
 				Status:  v1.ConditionTrue,
@@ -213,7 +282,72 @@ var _ = Describe("ExternalSecret controller", func() {
 		tc.pushsecret.Spec.SecretStoreRefs[0].Kind = "ClusterSecretStore"
 		tc.pushsecret.Spec.SecretStoreRefs[0].Kind = "ClusterSecretStore"
 		tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
 		tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
 			secretValue := secret.Data["key"]
 			secretValue := secret.Data["key"]
-			providerValue := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRefs[0].RemoteKey].Value
+			providerValue := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
+			expected := v1alpha1.PushSecretStatusCondition{
+				Type:    v1alpha1.PushSecretReady,
+				Status:  v1.ConditionTrue,
+				Reason:  v1alpha1.ReasonSynced,
+				Message: "PushSecret synced successfully",
+			}
+			return bytes.Equal(secretValue, providerValue) && checkCondition(ps.Status, expected)
+		}
+	}
+	// if target Secret name is not specified it should use the ExternalSecret name.
+	syncWithClusterStoreMatchingLabels := func(tc *testCase) {
+		fakeProvider.SetSecretFn = func() error {
+			return nil
+		}
+		tc.pushsecret = &v1alpha1.PushSecret{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      PushSecretName,
+				Namespace: PushSecretNamespace,
+			},
+			Spec: v1alpha1.PushSecretSpec{
+				SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
+					{
+						LabelSelector: &metav1.LabelSelector{
+							MatchLabels: map[string]string{
+								"foo": "bar",
+							},
+						},
+						Kind: "ClusterSecretStore",
+					},
+				},
+				Selector: v1alpha1.PushSecretSelector{
+					Secret: v1alpha1.PushSecretSecret{
+						Name: SecretName,
+					},
+				},
+				Data: []v1alpha1.PushSecretData{
+					{
+						Match: v1alpha1.PushSecretMatch{
+							SecretKey: "key",
+							RemoteRef: v1alpha1.PushSecretRemoteRef{
+								RemoteKey: "path/to/key",
+							},
+						},
+					},
+				},
+			},
+		}
+		tc.store = &v1beta1.ClusterSecretStore{
+			ObjectMeta: metav1.ObjectMeta{
+				Name: PushSecretStore,
+				Labels: map[string]string{
+					"foo": "bar",
+				},
+			},
+			Spec: v1beta1.SecretStoreSpec{
+				Provider: &v1beta1.SecretStoreProvider{
+					Fake: &v1beta1.FakeProvider{
+						Data: []v1beta1.FakeProviderData{},
+					},
+				},
+			},
+		}
+		tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
+			secretValue := secret.Data["key"]
+			providerValue := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
 			expected := v1alpha1.PushSecretStatusCondition{
 			expected := v1alpha1.PushSecretStatusCondition{
 				Type:    v1alpha1.PushSecretReady,
 				Type:    v1alpha1.PushSecretReady,
 				Status:  v1.ConditionTrue,
 				Status:  v1.ConditionTrue,
@@ -349,7 +483,9 @@ var _ = Describe("ExternalSecret controller", func() {
 			// this must be optional so we can test faulty es configuration
 			// this must be optional so we can test faulty es configuration
 		},
 		},
 		Entry("should sync", syncSuccessfully),
 		Entry("should sync", syncSuccessfully),
+		Entry("should sync to stores matching labels", syncMatchingLabels),
 		Entry("should sync with ClusterStore", syncWithClusterStore),
 		Entry("should sync with ClusterStore", syncWithClusterStore),
+		Entry("should sync with ClusterStore matching labels", syncWithClusterStoreMatchingLabels),
 		Entry("should fail if Secret is not created", failNoSecret),
 		Entry("should fail if Secret is not created", failNoSecret),
 		Entry("should fail if Secret Key does not exist", failNoSecretKey),
 		Entry("should fail if Secret Key does not exist", failNoSecretKey),
 		Entry("should fail if SetSecret fails", setSecretFail),
 		Entry("should fail if SetSecret fails", setSecretFail),

+ 1 - 1
pkg/provider/fake/fake_test.go

@@ -198,7 +198,7 @@ func TestSetSecret(t *testing.T) {
 				},
 				},
 			}, nil, "")
 			}, nil, "")
 			gomega.Expect(err).ToNot(gomega.HaveOccurred())
 			gomega.Expect(err).ToNot(gomega.HaveOccurred())
-			err = cl.SetSecret(context.TODO(), []byte(row.expValue), esv1alpha1.PushSecretRemoteRefs{
+			err = cl.SetSecret(context.TODO(), []byte(row.expValue), esv1alpha1.PushSecretRemoteRef{
 				RemoteKey: row.requestKey,
 				RemoteKey: row.requestKey,
 			})
 			})
 			if row.expErr != "" {
 			if row.expErr != "" {

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

@@ -85,7 +85,6 @@ type GoogleSecretManagerClient interface {
 var log = ctrl.Log.WithName("provider").WithName("gcp").WithName("secretsmanager")
 var log = ctrl.Log.WithName("provider").WithName("gcp").WithName("secretsmanager")
 
 
 // SetSecret pushes a kubernetes secret key into gcp provider Secret.
 // SetSecret pushes a kubernetes secret key into gcp provider Secret.
-// funcName(variable type_of_variable, ...)
 func (c *Client) SetSecret(ctx context.Context, payload []byte, remoteRef esv1beta1.PushRemoteRef) error {
 func (c *Client) SetSecret(ctx context.Context, payload []byte, remoteRef esv1beta1.PushRemoteRef) error {
 	createSecretReq := &secretmanagerpb.CreateSecretRequest{
 	createSecretReq := &secretmanagerpb.CreateSecretRequest{
 		Parent:   fmt.Sprintf("projects/%s", c.store.ProjectID),
 		Parent:   fmt.Sprintf("projects/%s", c.store.ProjectID),