Browse Source

Merge branch 'external-secrets:main' into feature/validate-gitlab-provider

Pedro Carmezim 4 years ago
parent
commit
3da29b1626

+ 3 - 0
ADOPTERS.md

@@ -6,6 +6,9 @@
 - [Pento](https://www.pento.io/)
 - [Mixpanel](https://mixpanel.com)
 - [K8S Website Infra](https://k8s.io/)
+- [Container Solutions](http://container-solutions.com/)
+- [Form3](https://www.form3.tech/)
+- [Pier Insurance](https://www.pier.digital/)
 
 
 Countless others that can't disclose that information! :)

+ 27 - 23
README.md

@@ -11,19 +11,19 @@ Multiple people and organizations are joining efforts to create a single Externa
 
 # Supported Backends
 
-- [AWS Secrets Manager](https://external-secrets.io/provider-aws-secrets-manager/)
-- [AWS Parameter Store](https://external-secrets.io/provider-aws-parameter-store/)
+- [AWS Secrets Manager](https://external-secrets.io/latest/provider-aws-secrets-manager/)
+- [AWS Parameter Store](https://external-secrets.io/latest/provider-aws-parameter-store/)
 - [Akeyless](https://www.akeyless.io/)
 - [Hashicorp Vault](https://www.vaultproject.io/)
-- [Google Cloud Secrets Manager](https://external-secrets.io/provider-google-secrets-manager/)
-- [Azure Key Vault](https://external-secrets.io/provider-azure-key-vault/)
-- [IBM Cloud Secrets Manager](https://external-secrets.io/provider-ibm-secrets-manager/)
-- [Yandex Lockbox](https://external-secrets.io/provider-yandex-lockbox/)
-- [Gitlab Project Variables](https://external-secrets.io/provider-gitlab-project-variables/)
+- [Google Cloud Secrets Manager](https://external-secrets.io/latest/provider-google-secrets-manager/)
+- [Azure Key Vault](https://external-secrets.io/latest/provider-azure-key-vault/)
+- [IBM Cloud Secrets Manager](https://external-secrets.io/latest/provider-ibm-secrets-manager/)
+- [Yandex Lockbox](https://external-secrets.io/latest/provider-yandex-lockbox/)
+- [Gitlab Project Variables](https://external-secrets.io/latest/provider-gitlab-project-variables/)
 - [Alibaba Cloud KMS](https://www.alibabacloud.com/product/kms) (Docs still missing, PRs welcomed!)
-- [Oracle Vault](https://external-secrets.io/provider-oracle-vault)
-- [Generic Webhook](https://external-secrets.io/provider-webhook)
-- [Kubernetes](https://external-secrets.io/provider-kubernetes)
+- [Oracle Vault](https://external-secrets.io/latest/provider-oracle-vault)
+- [Generic Webhook](https://external-secrets.io/latest/provider-webhook)
+- [Kubernetes](https://external-secrets.io/latest/provider-kubernetes)
 
 ## Stability and Support Level
 
@@ -31,23 +31,23 @@ Multiple people and organizations are joining efforts to create a single Externa
 
 | Provider                                                                 | Stability |                                        Contact |
 | ------------------------------------------------------------------------ | :-------: | ---------------------------------------------: |
-| [AWS SM](https://external-secrets.io/provider-aws-secrets-manager/)      |   stable   | [ESO Org](https://github.com/external-secrets) |
-| [AWS PS](https://external-secrets.io/provider-aws-parameter-store/)      |   stable   | [ESO Org](https://github.com/external-secrets) |
-| [Hashicorp Vault](https://external-secrets.io/provider-hashicorp-vault/) |   stable   | [ESO Org](https://github.com/external-secrets) |
-| [GCP SM](https://external-secrets.io/provider-google-secrets-manager/)   |   stable | [ESO Org](https://github.com/external-secrets) |
+| [AWS SM](https://external-secrets.io/latest/provider-aws-secrets-manager/)      |   stable   | [ESO Org](https://github.com/external-secrets) |
+| [AWS PS](https://external-secrets.io/latest/provider-aws-parameter-store/)      |   stable   | [ESO Org](https://github.com/external-secrets) |
+| [Hashicorp Vault](https://external-secrets.io/latest/provider-hashicorp-vault/) |   stable   | [ESO Org](https://github.com/external-secrets) |
+| [GCP SM](https://external-secrets.io/latest/provider-google-secrets-manager/)   |   stable | [ESO Org](https://github.com/external-secrets) |
 
 ### Community maintained:
 
 | Provider                                                            | Stability |                  Contact                   |
 | ------------------------------------------------------------------- | :-------: | :----------------------------------------: |
-| [Azure KV](https://external-secrets.io/provider-azure-key-vault/)   |   beta   | [@ahmedmus-1A](https://github.com/ahmedmus-1A) [@asnowfix](https://github.com/asnowfix) [@ncourbet-1A](https://github.com/ncourbet-1A) [@1A-mj](https://github.com/1A-mj) |
-| [IBM SM](https://external-secrets.io/provider-ibm-secrets-manager/) |   alpha   |   [@knelasevero](https://github.com/knelasevero) [@sebagomez](https://github.com/sebagomez) [@ricardoptcosta](https://github.com/ricardoptcosta)  |
-| [Yandex Lockbox](https://external-secrets.io/provider-yandex-lockbox/) |   alpha   |   [@AndreyZamyslov](https://github.com/AndreyZamyslov) [@knelasevero](https://github.com/knelasevero)          |
-| [Gitlab Project Variables](https://external-secrets.io/provider-gitlab-project-variables/) |   alpha   |   [@Jabray5](https://github.com/Jabray5)          |
+| [Azure KV](https://external-secrets.io/latest/provider-azure-key-vault/)   |   beta   | [@ahmedmus-1A](https://github.com/ahmedmus-1A) [@asnowfix](https://github.com/asnowfix) [@ncourbet-1A](https://github.com/ncourbet-1A) [@1A-mj](https://github.com/1A-mj) |
+| [IBM SM](https://external-secrets.io/latest/provider-ibm-secrets-manager/) |   alpha   |   [@knelasevero](https://github.com/knelasevero) [@sebagomez](https://github.com/sebagomez) [@ricardoptcosta](https://github.com/ricardoptcosta)  |
+| [Yandex Lockbox](https://external-secrets.io/latest/provider-yandex-lockbox/) |   alpha   |   [@AndreyZamyslov](https://github.com/AndreyZamyslov) [@knelasevero](https://github.com/knelasevero)          |
+| [Gitlab Project Variables](https://external-secrets.io/latest/provider-gitlab-project-variables/) |   alpha   |   [@Jabray5](https://github.com/Jabray5)          |
 | Alibaba Cloud KMS                                                   |   alpha  | [@ElsaChelala](https://github.com/ElsaChelala)                                |
-| [Oracle Vault]( https://external-secrets.io/provider-oracle-vault)  |   alpha  | [@KianTigger](https://github.com/KianTigger) [@EladGabay](https://github.com/EladGabay) |
-| [Akeyless]( https://external-secrets.io/provider-akeyless)  |   alpha  | [@renanaAkeyless](https://github.com/renanaAkeyless)                                 |
-| [Generic Webhook](https://external-secrets.io/provider-webhook)  |  alpha  | [@willemm](https://github.com/willemm) |
+| [Oracle Vault]( https://external-secrets.io/latest/provider-oracle-vault)  |   alpha  | [@KianTigger](https://github.com/KianTigger) [@EladGabay](https://github.com/EladGabay) |
+| [Akeyless]( https://external-secrets.io/latest/provider-akeyless)  |   alpha  | [@renanaAkeyless](https://github.com/renanaAkeyless)                                 |
+| [Generic Webhook](https://external-secrets.io/latest/provider-webhook)  |  alpha  | [@willemm](https://github.com/willemm) |
 
 ## Documentation
 
@@ -61,7 +61,7 @@ Even though we have active maintainers and people assigned to this project, we k
 
 ## Contributing
 
-We welcome and encourage contributions to this project! Please read the [Developer](https://www.external-secrets.io/contributing-devguide/) and [Contribution process](https://www.external-secrets.io/contributing-process/) guides. Also make sure to check the [Code of Conduct](https://www.external-secrets.io/contributing-coc/) and adhere to its guidelines.
+We welcome and encourage contributions to this project! Please read the [Developer](https://www.external-secrets.io/latest/contributing-devguide/) and [Contribution process](https://www.external-secrets.io/latest/contributing-process/) guides. Also make sure to check the [Code of Conduct](https://www.external-secrets.io/latest/contributing-coc/) and adhere to its guidelines.
 
 ## Bi-weekly Development Meeting
 
@@ -79,5 +79,9 @@ Please create a PR and add your company or your project to our [ADOPTERS](ADOPTE
 
 ## Kicked off by
 
-![](assets/CS_logo_1.png)
 ![](assets/Godaddylogo_2020.png)
+
+## Sponsored by
+
+![](assets/CS_logo_1.png)
+![](assets/form3_logo.png)

BIN
assets/form3_logo.png


+ 2 - 2
deploy/charts/external-secrets/Chart.yaml

@@ -2,8 +2,8 @@ apiVersion: v2
 name: external-secrets
 description: External secret management for Kubernetes
 type: application
-version: "0.5.0"
-appVersion: "v0.5.0"
+version: "0.5.1"
+appVersion: "v0.5.1"
 kubeVersion: ">= 1.11.0-0"
 keywords:
   - kubernetes-external-secrets

+ 1 - 1
deploy/charts/external-secrets/README.md

@@ -4,7 +4,7 @@
 
 [//]: # (README.md generated by gotmpl. DO NOT EDIT.)
 
-![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![Version: 0.5.0](https://img.shields.io/badge/Version-0.5.0-informational?style=flat-square)
+![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![Version: 0.5.1](https://img.shields.io/badge/Version-0.5.1-informational?style=flat-square)
 
 External secret management for Kubernetes
 

+ 1 - 1
deploy/charts/external-secrets/templates/cert-controller-rbac.yaml

@@ -1,4 +1,4 @@
-{{- if .Values.certController.rbac.create -}}
+{{- if and .Values.certController.create .Values.certController.rbac.create -}}
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRole
 metadata:

+ 5 - 1
docs/index.md

@@ -47,5 +47,9 @@ How to get involved:
 
 ### Kicked off by
 
+![godaddy-logo](./pictures/godaddy_logo.png)
+
+### Sponsored by
+
 ![cs-logo](./pictures/cs_logo.png)
-![godaddy-logo](./pictures/godaddy_logo.png)
+![Form3](./pictures/form3_logo.png)

BIN
docs/pictures/form3_logo.png


+ 22 - 31
docs/provider-kubernetes.md

@@ -2,35 +2,30 @@ External Secrets Operator allows to retrieve in-cluster secrets or from a remote
 
 ### Authentication
 
-It's possible to authenticate against the Kubernetes API using client certificates, a bearer token or a service account (not implemented yet). The operator enforces that exactly one authentication method is used.
+It's possible to authenticate against the Kubernetes API using client certificates or a bearer token. Authentication using a service account has not yet been implemented. The operator enforces that exactly one authentication method is used.
 
 **NOTE:** `SelfSubjectAccessReview` permission is required for the service account in order to validation work properly.
 
 ## Example
 
-### In-cluster secrets using Client certificates
+### In-cluster secrets using a Token
+
+1. Create a K8s Secret with a client token for the default service account
 
-1. Create a K8s Secret with the encoded base64 ca and client certificates
-   
 ```
 apiVersion: v1
 kind: Secret
 metadata:
-  name: cluster-secrets
-data:
-  # Fill with your encoded base64 CA
-  certificate-authority-data: Cg==
-  # Fill with your encoded base64 Certificate
-  client-certificate-data: Cg==
-  # Fill with your encoded base64 Key
-  client-key-data: Cg==
+  name: mydefaulttoken
+  annotations:
+    kubernetes.io/service-account.name: default
+type: kubernetes.io/service-account-token
 ```
 2. Create a SecretStore
 
-The Servers `url` won't be present as it will default to `kubernetes.default`, add a proper value if needed. In this example the Certificate Authority is fetch using the referenced `caProvider`.
-
-The `auth` section indicates that the type `cert`  will be used for authentication, it includes the path to fetch the client certificate and key.
+The Servers `url` won't be present as it will default to `kubernetes.default`, add a proper value if needed. In this example the Certificate Authority is fetched using the referenced `caProvider`.
 
+The `auth` section indicates that the type `token` will be used for authentication, it includes the path to fetch the token. Set `remoteNamespace` to the name of the namespace where your target secrets reside.
 
 ```
 apiVersion: external-secrets.io/v1beta1
@@ -39,22 +34,18 @@ metadata:
   name: example
 spec:
   provider:
-      kubernetes: 
-        server: 
-          # referenced caProvider
-          caProvider: 
-            type: Secret
-            name : cluster-secrets
-            key: certificate-authority-data
+    kubernetes:
+      server: 
+        caProvider: 
+          type: Secret
+          name: mydefaulttoken
+          key: ca.crt
         auth:
-          # referenced client certificates
-          cert:
-            clientCert: 
-                name: cluster-secrets
-                key: certificate
-            clientKey: 
-                name: cluster-secrets
-                key: key
+          token:
+            bearerToken: 
+              name: mydefaulttoken
+              key: token
+        remoteNamespace: default
 ```
 3. Create the local secret that will be synced 
               
@@ -152,4 +143,4 @@ spec:
     remoteRef:
       key: secret-remote-example
       property: extra
-```
+```

+ 4 - 0
e2e/suite/gcp/gcp.go

@@ -46,6 +46,10 @@ var _ = Describe("[gcp]", Label("gcp", "secretsmanager"), func() {
 		Entry(common.SSHKeySyncDataProperty(f)),
 		Entry(common.SyncWithoutTargetName(f)),
 		Entry(common.JSONDataWithoutTargetName(f)),
+		Entry(common.FindByName(f)),
+		Entry(common.FindByNameWithPath(f)),
+		Entry(common.FindByTag(f)),
+		Entry(common.FindByTagWithPath(f)),
 		Entry(common.SyncV1Alpha1(f)),
 		Entry("should sync p12 encoded cert secret", p12Cert),
 	)

+ 1 - 0
e2e/suite/gcp/provider.go

@@ -113,6 +113,7 @@ func (s *GcpProvider) CreateSecret(key string, val framework.SecretEntry) {
 		Parent:   fmt.Sprintf("projects/%s", s.projectID),
 		SecretId: key,
 		Secret: &secretmanagerpb.Secret{
+			Labels: val.Tags,
 			Replication: &secretmanagerpb.Replication{
 				Replication: &secretmanagerpb.Replication_Automatic_{
 					Automatic: &secretmanagerpb.Replication_Automatic{},

+ 1 - 1
pkg/provider/aws/secretsmanager/secretsmanager.go

@@ -89,7 +89,7 @@ func (sm *SecretsManager) fetch(_ context.Context, ref esv1beta1.ExternalSecretD
 	return secretOut, nil
 }
 
-// Empty GetAllSecrets.
+// GetAllSecrets syncs multiple secrets from aws provider into a single Kubernetes Secret.
 func (sm *SecretsManager) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	if ref.Name != nil {
 		return sm.findByName(ctx, ref)

+ 9 - 4
pkg/provider/gcp/secretmanager/fake/fake.go

@@ -17,21 +17,26 @@ import (
 	"context"
 	"fmt"
 
+	secretmanager "cloud.google.com/go/secretmanager/apiv1"
 	"github.com/google/go-cmp/cmp"
 	"github.com/google/go-cmp/cmp/cmpopts"
-	grpc "github.com/googleapis/gax-go/v2"
+	"github.com/googleapis/gax-go/v2"
 	secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1"
 )
 
 type MockSMClient struct {
-	accessSecretFn func(ctx context.Context, req *secretmanagerpb.AccessSecretVersionRequest, opts ...grpc.CallOption) (*secretmanagerpb.AccessSecretVersionResponse, error)
+	accessSecretFn func(ctx context.Context, req *secretmanagerpb.AccessSecretVersionRequest, opts ...gax.CallOption) (*secretmanagerpb.AccessSecretVersionResponse, error)
+	ListSecretsFn  func(ctx context.Context, req *secretmanagerpb.ListSecretsRequest, opts ...gax.CallOption) *secretmanager.SecretIterator
 	closeFn        func() error
 }
 
-func (mc *MockSMClient) AccessSecretVersion(ctx context.Context, req *secretmanagerpb.AccessSecretVersionRequest, opts ...grpc.CallOption) (*secretmanagerpb.AccessSecretVersionResponse, error) {
+func (mc *MockSMClient) AccessSecretVersion(ctx context.Context, req *secretmanagerpb.AccessSecretVersionRequest, opts ...gax.CallOption) (*secretmanagerpb.AccessSecretVersionResponse, error) {
 	return mc.accessSecretFn(ctx, req)
 }
 
+func (mc *MockSMClient) ListSecrets(ctx context.Context, req *secretmanagerpb.ListSecretsRequest, opts ...gax.CallOption) *secretmanager.SecretIterator {
+	return mc.ListSecretsFn(ctx, req)
+}
 func (mc *MockSMClient) Close() error {
 	return mc.closeFn()
 }
@@ -44,7 +49,7 @@ func (mc *MockSMClient) NilClose() {
 
 func (mc *MockSMClient) WithValue(ctx context.Context, req *secretmanagerpb.AccessSecretVersionRequest, val *secretmanagerpb.AccessSecretVersionResponse, err error) {
 	if mc != nil {
-		mc.accessSecretFn = func(paramCtx context.Context, paramReq *secretmanagerpb.AccessSecretVersionRequest, paramOpts ...grpc.CallOption) (*secretmanagerpb.AccessSecretVersionResponse, error) {
+		mc.accessSecretFn = func(paramCtx context.Context, paramReq *secretmanagerpb.AccessSecretVersionRequest, paramOpts ...gax.CallOption) (*secretmanagerpb.AccessSecretVersionResponse, error) {
 			// type secretmanagerpb.AccessSecretVersionRequest contains unexported fields
 			// use cmpopts.IgnoreUnexported to ignore all the unexported fields in the cmp.
 			if !cmp.Equal(paramReq, req, cmpopts.IgnoreUnexported(secretmanagerpb.AccessSecretVersionRequest{})) {

+ 147 - 14
pkg/provider/gcp/secretmanager/secretsmanager.go

@@ -16,7 +16,10 @@ package secretmanager
 import (
 	"context"
 	"encoding/json"
+	"errors"
 	"fmt"
+	"strconv"
+	"strings"
 	"sync"
 
 	secretmanager "cloud.google.com/go/secretmanager/apiv1"
@@ -24,13 +27,16 @@ import (
 	"github.com/tidwall/gjson"
 	"golang.org/x/oauth2"
 	"golang.org/x/oauth2/google"
+	"google.golang.org/api/iterator"
 	"google.golang.org/api/option"
 	secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1"
 	v1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/types"
+	ctrl "sigs.k8s.io/controller-runtime"
 	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"
 )
 
@@ -52,16 +58,20 @@ const (
 	errClientGetSecretAccess                  = "unable to access Secret from SecretManager Client: %w"
 	errJSONSecretUnmarshal                    = "unable to unmarshal secret: %w"
 
-	errInvalidStore         = "invalid store"
-	errInvalidStoreSpec     = "invalid store spec"
-	errInvalidStoreProv     = "invalid store provider"
-	errInvalidGCPProv       = "invalid gcp secrets manager provider"
-	errInvalidAuthSecretRef = "invalid auth secret ref: %w"
-	errInvalidWISARef       = "invalid workload identity service account reference: %w"
+	errInvalidStore           = "invalid store"
+	errInvalidStoreSpec       = "invalid store spec"
+	errInvalidStoreProv       = "invalid store provider"
+	errInvalidGCPProv         = "invalid gcp secrets manager provider"
+	errInvalidAuthSecretRef   = "invalid auth secret ref: %w"
+	errInvalidWISARef         = "invalid workload identity service account reference: %w"
+	errUnexpectedFindOperator = "unexpected find operator"
 )
 
+var log = ctrl.Log.WithName("provider").WithName("gcp").WithName("secretsmanager")
+
 type GoogleSecretManagerClient interface {
 	AccessSecretVersion(ctx context.Context, req *secretmanagerpb.AccessSecretVersionRequest, opts ...gax.CallOption) (*secretmanagerpb.AccessSecretVersionResponse, error)
+	ListSecrets(ctx context.Context, req *secretmanagerpb.ListSecretsRequest, opts ...gax.CallOption) *secretmanager.SecretIterator
 	Close() error
 }
 
@@ -82,10 +92,11 @@ type ProviderGCP struct {
 }
 
 type gClient struct {
-	kube             kclient.Client
-	store            *esv1beta1.GCPSMProvider
-	namespace        string
-	storeKind        string
+	kube      kclient.Client
+	store     *esv1beta1.GCPSMProvider
+	namespace string
+	storeKind string
+
 	workloadIdentity *workloadIdentity
 }
 
@@ -200,10 +211,124 @@ func (sm *ProviderGCP) NewClient(ctx context.Context, store esv1beta1.GenericSto
 	return sm, nil
 }
 
-// Empty GetAllSecrets.
+// GetAllSecrets syncs multiple secrets from gcp provider into a single Kubernetes Secret.
 func (sm *ProviderGCP) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
-	// TO be implemented
-	return nil, fmt.Errorf("GetAllSecrets not implemented")
+	if ref.Name != nil {
+		return sm.findByName(ctx, ref)
+	}
+	if len(ref.Tags) > 0 {
+		return sm.findByTags(ctx, ref)
+	}
+	return nil, errors.New(errUnexpectedFindOperator)
+}
+
+func (sm *ProviderGCP) findByName(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
+	// regex matcher
+	matcher, err := find.New(*ref.Name)
+	if err != nil {
+		return nil, err
+	}
+	req := &secretmanagerpb.ListSecretsRequest{
+		Parent: fmt.Sprintf("projects/%s", sm.projectID),
+	}
+	if ref.Path != nil {
+		req.Filter = fmt.Sprintf("name:%s", *ref.Path)
+	}
+	// Call the API.
+	it := sm.SecretManagerClient.ListSecrets(ctx, req)
+	secretMap := make(map[string][]byte)
+	for {
+		resp, err := it.Next()
+		if errors.Is(err, iterator.Done) {
+			break
+		}
+		if err != nil {
+			return nil, fmt.Errorf("failed to list secrets: %w", err)
+		}
+		log.V(1).Info("gcp sm findByName found", "secrets", strconv.Itoa(it.PageInfo().Remaining()))
+		key := sm.trimName(resp.Name)
+		// If we don't match we skip.
+		// Also, if we have path, and it is not at the beguining we skip.
+		// We have to check if path is at the beguining of the key because
+		// there is no way to create a `name:%s*` (starts with) filter
+		// At https://cloud.google.com/secret-manager/docs/filtering you can use `*`
+		// but not like that it seems.
+		if !matcher.MatchName(key) || (ref.Path != nil && !strings.HasPrefix(key, *ref.Path)) {
+			continue
+		}
+		log.V(1).Info("gcp sm findByName matches", "name", resp.Name)
+		secretMap[key], err = sm.getData(ctx, key)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return utils.ConvertKeys(ref.ConversionStrategy, secretMap)
+}
+
+func (sm *ProviderGCP) getData(ctx context.Context, key string) ([]byte, error) {
+	dataRef := esv1beta1.ExternalSecretDataRemoteRef{
+		Key: key,
+	}
+	data, err := sm.GetSecret(ctx, dataRef)
+	if err != nil {
+		return []byte(""), err
+	}
+	return data, nil
+}
+
+func (sm *ProviderGCP) findByTags(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
+	var tagFilter string
+	for k, v := range ref.Tags {
+		tagFilter = fmt.Sprintf("%slabels.%s=%s ", tagFilter, k, v)
+	}
+	tagFilter = strings.TrimSuffix(tagFilter, " ")
+	if ref.Path != nil {
+		tagFilter = fmt.Sprintf("%s name:%s", tagFilter, *ref.Path)
+	}
+	req := &secretmanagerpb.ListSecretsRequest{
+		Parent: fmt.Sprintf("projects/%s", sm.projectID),
+	}
+	log.V(1).Info("gcp sm findByTags", "tagFilter", tagFilter)
+	req.Filter = tagFilter
+	// Call the API.
+	it := sm.SecretManagerClient.ListSecrets(ctx, req)
+	secretMap := make(map[string][]byte)
+	for {
+		resp, err := it.Next()
+		if errors.Is(err, iterator.Done) {
+			break
+		}
+		if err != nil {
+			return nil, fmt.Errorf("failed to list secrets: %w", err)
+		}
+		key := sm.trimName(resp.Name)
+		if ref.Path != nil && !strings.HasPrefix(key, *ref.Path) {
+			continue
+		}
+		log.V(1).Info("gcp sm findByTags matches tags", "name", resp.Name)
+		secretMap[key], err = sm.getData(ctx, key)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return utils.ConvertKeys(ref.ConversionStrategy, secretMap)
+}
+
+func (sm *ProviderGCP) trimName(name string) string {
+	projectIDNumuber := sm.extractProjectIDNumber(name)
+	key := strings.TrimPrefix(name, fmt.Sprintf("projects/%s/secrets/", projectIDNumuber))
+	return key
+}
+
+// extractProjectIDNumber grabs the project id from the full name returned by gcp api
+// gcp api seems to always return the number and not the project name
+// (and users would always use the name, while requests accept both).
+func (sm *ProviderGCP) extractProjectIDNumber(secretFullName string) string {
+	s := strings.Split(secretFullName, "/")
+	projectIDNumuber := s[1]
+	return projectIDNumuber
 }
 
 // GetSecret returns a single secret from the provider.
@@ -236,7 +361,15 @@ func (sm *ProviderGCP) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecr
 	if result.Payload.Data != nil {
 		payload = string(result.Payload.Data)
 	}
-
+	idx := strings.Index(ref.Property, ".")
+	refProperty := ref.Property
+	if idx > 0 {
+		refProperty = strings.ReplaceAll(refProperty, ".", "\\.")
+		val := gjson.Get(payload, refProperty)
+		if val.Exists() {
+			return []byte(val.String()), nil
+		}
+	}
 	val := gjson.Get(payload, ref.Property)
 	if !val.Exists() {
 		return nil, fmt.Errorf("key %s does not exist in secret %s", ref.Property, ref.Key)

+ 20 - 0
pkg/provider/gcp/secretmanager/secretsmanager_test.go

@@ -109,6 +109,25 @@ func TestSecretManagerGetSecret(t *testing.T) {
 		smtc.apiOutput.Payload.Data = []byte("testtesttest")
 		smtc.expectedSecret = "testtesttest"
 	}
+	// good case: with a dot in the key name
+	setDotRef := func(smtc *secretManagerTestCase) {
+		smtc.ref = &esv1beta1.ExternalSecretDataRemoteRef{
+			Key:      "/baz",
+			Version:  "default",
+			Property: "name.json",
+		}
+		smtc.apiInput.Name = "projects/default/secrets//baz/versions/default"
+		smtc.apiOutput.Payload.Data = []byte(
+			`{
+			"name.json": "Tom",
+			"friends": [
+				{"first": "Dale", "last": "Murphy"},
+				{"first": "Roger", "last": "Craig"},
+				{"first": "Jane", "last": "Murphy"}
+			]
+        }`)
+		smtc.expectedSecret = "Tom"
+	}
 
 	// good case: ref with
 	setCustomRef := func(smtc *secretManagerTestCase) {
@@ -144,6 +163,7 @@ func TestSecretManagerGetSecret(t *testing.T) {
 		makeValidSecretManagerTestCaseCustom(setCustomVersion),
 		makeValidSecretManagerTestCaseCustom(setAPIErr),
 		makeValidSecretManagerTestCaseCustom(setCustomRef),
+		makeValidSecretManagerTestCaseCustom(setDotRef),
 		makeValidSecretManagerTestCaseCustom(setNilMockClient),
 	}
 

+ 8 - 11
pkg/provider/vault/vault.go

@@ -96,6 +96,7 @@ const (
 	errInvalidClientCert = "invalid Auth.Cert.ClientCert: %w"
 	errInvalidCertSec    = "invalid Auth.Cert.SecretRef: %w"
 	errInvalidJwtSec     = "invalid Auth.Jwt.SecretRef: %w"
+	errInvalidJwtK8sSA   = "invalid Auth.Jwt.KubernetesServiceAccountToken.ServiceAccountRef: %w"
 	errInvalidKubeSA     = "invalid Auth.Kubernetes.ServiceAccountRef: %w"
 	errInvalidKubeSec    = "invalid Auth.Kubernetes.SecretRef: %w"
 	errInvalidLdapSec    = "invalid Auth.Ldap.SecretRef: %w"
@@ -231,7 +232,7 @@ func (c *connector) ValidateStore(store esv1beta1.GenericStore) error {
 			}
 		} else if p.Auth.Jwt.KubernetesServiceAccountToken != nil {
 			if err := utils.ValidateServiceAccountSelector(store, p.Auth.Jwt.KubernetesServiceAccountToken.ServiceAccountRef); err != nil {
-				return fmt.Errorf(errInvalidJwtSec, err)
+				return fmt.Errorf(errInvalidJwtK8sSA, err)
 			}
 		} else {
 			return fmt.Errorf(errJwtNoTokenSource)
@@ -279,12 +280,12 @@ func (v *client) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecret
 		return nil, err
 	}
 	if ref.Name != nil {
-		return v.findSecretsFromName(ctx, potentialSecrets, *ref.Name, searchPath)
+		return v.findSecretsFromName(ctx, potentialSecrets, *ref.Name)
 	}
-	return v.findSecretsFromTags(ctx, potentialSecrets, ref.Tags, searchPath)
+	return v.findSecretsFromTags(ctx, potentialSecrets, ref.Tags)
 }
 
-func (v *client) findSecretsFromTags(ctx context.Context, candidates []string, tags map[string]string, removeFromName string) (map[string][]byte, error) {
+func (v *client) findSecretsFromTags(ctx context.Context, candidates []string, tags map[string]string) (map[string][]byte, error) {
 	secrets := make(map[string][]byte)
 	for _, name := range candidates {
 		match := true
@@ -304,16 +305,13 @@ func (v *client) findSecretsFromTags(ctx context.Context, candidates []string, t
 			if err != nil {
 				return nil, err
 			}
-			if removeFromName != "" {
-				name = strings.TrimPrefix(name, removeFromName)
-			}
 			secrets[name] = secret
 		}
 	}
 	return secrets, nil
 }
 
-func (v *client) findSecretsFromName(ctx context.Context, candidates []string, ref esv1beta1.FindName, removeFromName string) (map[string][]byte, error) {
+func (v *client) findSecretsFromName(ctx context.Context, candidates []string, ref esv1beta1.FindName) (map[string][]byte, error) {
 	secrets := make(map[string][]byte)
 	matcher, err := find.New(ref)
 	if err != nil {
@@ -326,9 +324,6 @@ func (v *client) findSecretsFromName(ctx context.Context, candidates []string, r
 			if err != nil {
 				return nil, err
 			}
-			if removeFromName != "" {
-				name = strings.TrimPrefix(name, removeFromName)
-			}
 			secrets[name] = secret
 		}
 	}
@@ -591,6 +586,8 @@ func (v *client) readSecret(ctx context.Context, path, version string) (map[stri
 func (v *client) newConfig() (*vault.Config, error) {
 	cfg := vault.DefaultConfig()
 	cfg.Address = v.store.Server
+	// In a controller-runtime context, we rely on the reconciliation process for retrying
+	cfg.MaxRetries = 0
 
 	if len(v.store.CABundle) == 0 && v.store.CAProvider == nil {
 		return cfg, nil

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

@@ -1167,8 +1167,8 @@ func TestGetAllSecrets(t *testing.T) {
 			want: want{
 				err: nil,
 				val: map[string][]byte{
-					"1": path1Bytes,
-					"2": path2Bytes,
+					"path/1": path1Bytes,
+					"path/2": path2Bytes,
 				},
 			},
 		},