Browse Source

Merge pull request #959 from external-secrets/chore/refactor-vault

Chore/refactor vault
paul-the-alien[bot] 4 years ago
parent
commit
84af221762
7 changed files with 434 additions and 499 deletions
  1. 2 2
      e2e/framework/addon/vault.go
  2. 4 4
      e2e/suite/vault/provider.go
  3. 4 1
      go.mod
  4. 11 2
      go.sum
  5. 89 63
      pkg/provider/vault/fake/vault.go
  6. 182 207
      pkg/provider/vault/vault.go
  7. 142 220
      pkg/provider/vault/vault_test.go

+ 2 - 2
e2e/framework/addon/vault.go

@@ -251,7 +251,7 @@ func (l *Vault) configureVault() error {
 	// configure appRole
 	l.AppRolePath = "myapprole"
 	req := l.VaultClient.NewRequest(http.MethodGet, fmt.Sprintf("/v1/auth/%s/role/eso-e2e-role/role-id", l.AppRolePath))
-	res, err := l.VaultClient.RawRequest(req)
+	res, err := l.VaultClient.RawRequest(req) //nolint:staticcheck
 	if err != nil {
 		return err
 	}
@@ -265,7 +265,7 @@ func (l *Vault) configureVault() error {
 
 	// parse role id
 	req = l.VaultClient.NewRequest(http.MethodPost, fmt.Sprintf("/v1/auth/%s/role/eso-e2e-role/secret-id", l.AppRolePath))
-	res, err = l.VaultClient.RawRequest(req)
+	res, err = l.VaultClient.RawRequest(req) //nolint:staticcheck
 	if err != nil {
 		return err
 	}

+ 4 - 4
e2e/suite/vault/provider.go

@@ -65,22 +65,22 @@ func newVaultProvider(f *framework.Framework) *vaultProvider {
 func (s *vaultProvider) CreateSecret(key string, val framework.SecretEntry) {
 	req := s.client.NewRequest(http.MethodPost, fmt.Sprintf("/v1/secret/data/%s", key))
 	req.BodyBytes = []byte(fmt.Sprintf(`{"data": %s}`, val.Value))
-	_, err := s.client.RawRequestWithContext(context.Background(), req)
+	_, err := s.client.RawRequestWithContext(context.Background(), req) //nolint:staticcheck
 	Expect(err).ToNot(HaveOccurred())
 
 	req = s.client.NewRequest(http.MethodPost, fmt.Sprintf("/v1/secret_v1/%s", key))
 	req.BodyBytes = []byte(val.Value)
-	_, err = s.client.RawRequestWithContext(context.Background(), req)
+	_, err = s.client.RawRequestWithContext(context.Background(), req) //nolint:staticcheck
 	Expect(err).ToNot(HaveOccurred())
 }
 
 func (s *vaultProvider) DeleteSecret(key string) {
 	req := s.client.NewRequest(http.MethodDelete, fmt.Sprintf("/v1/secret/data/%s", key))
-	_, err := s.client.RawRequestWithContext(context.Background(), req)
+	_, err := s.client.RawRequestWithContext(context.Background(), req) //nolint:staticcheck
 	Expect(err).ToNot(HaveOccurred())
 
 	req = s.client.NewRequest(http.MethodDelete, fmt.Sprintf("/v1/secret_v1/%s", key))
-	_, err = s.client.RawRequestWithContext(context.Background(), req)
+	_, err = s.client.RawRequestWithContext(context.Background(), req) //nolint:staticcheck
 	Expect(err).ToNot(HaveOccurred())
 }
 

+ 4 - 1
go.mod

@@ -57,7 +57,10 @@ require (
 	github.com/google/go-cmp v0.5.7
 	github.com/google/uuid v1.3.0
 	github.com/googleapis/gax-go/v2 v2.2.0
-	github.com/hashicorp/vault/api v1.4.1
+	github.com/hashicorp/vault/api v1.5.0
+	github.com/hashicorp/vault/api/auth/approle v0.1.1
+	github.com/hashicorp/vault/api/auth/kubernetes v0.1.0
+	github.com/hashicorp/vault/api/auth/ldap v0.1.0
 	github.com/huandu/xstrings v1.3.2 // indirect
 	github.com/lestrrat-go/jwx v1.2.22
 	github.com/onsi/ginkgo/v2 v2.1.3

+ 11 - 2
go.sum

@@ -489,8 +489,17 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
 github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
 github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
 github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
-github.com/hashicorp/vault/api v1.4.1 h1:mWLfPT0RhxBitjKr6swieCEP2v5pp/M//t70S3kMLRo=
-github.com/hashicorp/vault/api v1.4.1/go.mod h1:LkMdrZnWNrFaQyYYazWVn7KshilfDidgVBq6YiTq/bM=
+github.com/hashicorp/vault/api v1.3.0/go.mod h1:EabNQLI0VWbWoGlA+oBLC8PXmR9D60aUVgQGvangFWQ=
+github.com/hashicorp/vault/api v1.3.1/go.mod h1:QeJoWxMFt+MsuWcYhmwRLwKEXrjwAFFywzhptMsTIUw=
+github.com/hashicorp/vault/api v1.5.0 h1:Bp6yc2bn7CWkOrVIzFT/Qurzx528bdavF3nz590eu28=
+github.com/hashicorp/vault/api v1.5.0/go.mod h1:LkMdrZnWNrFaQyYYazWVn7KshilfDidgVBq6YiTq/bM=
+github.com/hashicorp/vault/api/auth/approle v0.1.1 h1:R5yA+xcNvw1ix6bDuWOaLOq2L4L77zDCVsethNw97xQ=
+github.com/hashicorp/vault/api/auth/approle v0.1.1/go.mod h1:mHOLgh//xDx4dpqXoq6tS8Ob0FoCFWLU2ibJ26Lfmag=
+github.com/hashicorp/vault/api/auth/kubernetes v0.1.0 h1:6BtyahbF4aQp8gg3ww0A/oIoqzbhpNP1spXU3nHE0n0=
+github.com/hashicorp/vault/api/auth/kubernetes v0.1.0/go.mod h1:Pdgk78uIs0mgDOLvc3a+h/vYIT9rznw2sz+ucuH9024=
+github.com/hashicorp/vault/api/auth/ldap v0.1.0 h1:runn+BIRU6/QcGirhstoJIqO+plVuTN/zf401tbB5H0=
+github.com/hashicorp/vault/api/auth/ldap v0.1.0/go.mod h1:vl3YZyt+bRtTHvVqKWeOTCI5I40t31t0S48efipZq64=
+github.com/hashicorp/vault/sdk v0.3.0/go.mod h1:aZ3fNuL5VNydQk8GcLJ2TV8YCRVvyaakYkhZRoVuhj0=
 github.com/hashicorp/vault/sdk v0.4.1 h1:3SaHOJY687jY1fnB61PtL0cOkKItphrbLmux7T92HBo=
 github.com/hashicorp/vault/sdk v0.4.1/go.mod h1:aZ3fNuL5VNydQk8GcLJ2TV8YCRVvyaakYkhZRoVuhj0=
 github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=

+ 89 - 63
pkg/provider/vault/fake/vault.go

@@ -16,79 +16,78 @@ package fake
 
 import (
 	"context"
-	"net/url"
-	"strings"
 
 	vault "github.com/hashicorp/vault/api"
 )
 
-type MockNewRequestFn func(method, requestPath string) *vault.Request
+type LoginFn func(ctx context.Context, authMethod vault.AuthMethod) (*vault.Secret, error)
+type Auth struct {
+	LoginFn LoginFn
+}
 
-type MockRawRequestWithContextFn func(ctx context.Context, r *vault.Request) (*vault.Response, error)
+func (f Auth) Login(ctx context.Context, authMethod vault.AuthMethod) (*vault.Secret, error) {
+	return f.LoginFn(ctx, authMethod)
+}
 
-type MockSetTokenFn func(v string)
+type ReadWithDataWithContextFn func(ctx context.Context, path string, data map[string][]string) (*vault.Secret, error)
+type ListWithContextFn func(ctx context.Context, path string) (*vault.Secret, error)
+type WriteWithContextFn func(ctx context.Context, path string, data map[string]interface{}) (*vault.Secret, error)
 
-type MockTokenFn func() string
+type Logical struct {
+	ReadWithDataWithContextFn ReadWithDataWithContextFn
+	ListWithContextFn         ListWithContextFn
+	WriteWithContextFn        WriteWithContextFn
+}
 
-type MockClearTokenFn func()
+func NewReadWithContextFn(secret map[string]interface{}, err error) ReadWithDataWithContextFn {
+	return func(ctx context.Context, path string, data map[string][]string) (*vault.Secret, error) {
+		vault := &vault.Secret{
+			Data: secret,
+		}
+		return vault, err
+	}
+}
 
-type MockSetNamespaceFn func(namespace string)
+func (f Logical) ReadWithDataWithContext(ctx context.Context, path string, data map[string][]string) (*vault.Secret, error) {
+	return f.ReadWithDataWithContextFn(ctx, path, data)
+}
+func (f Logical) ListWithContext(ctx context.Context, path string) (*vault.Secret, error) {
+	return f.ListWithContextFn(ctx, path)
+}
+func (f Logical) WriteWithContext(ctx context.Context, path string, data map[string]interface{}) (*vault.Secret, error) {
+	return f.WriteWithContextFn(ctx, path, data)
+}
 
-type MockAddHeaderFn func(key, value string)
+type RevokeSelfWithContextFn func(ctx context.Context, token string) error
+type LookupSelfWithContextFn func(ctx context.Context) (*vault.Secret, error)
 
-func NewMockNewRequestFn(req *vault.Request) MockNewRequestFn {
-	return func(method, requestPath string) *vault.Request {
-		return req
-	}
+type Token struct {
+	RevokeSelfWithContextFn RevokeSelfWithContextFn
+	LookupSelfWithContextFn LookupSelfWithContextFn
 }
 
-func NewMockNewRequestListFn(req *vault.Request) MockNewRequestFn {
-	return func(method, requestPath string) *vault.Request {
-		urlPath := url.URL{
-			Path: requestPath,
-		}
-		req.URL = &urlPath
-		req.Params = make(url.Values)
-		return req
-	}
+func (f Token) RevokeSelfWithContext(ctx context.Context, token string) error {
+	return f.RevokeSelfWithContextFn(ctx, token)
+}
+func (f Token) LookupSelfWithContext(ctx context.Context) (*vault.Secret, error) {
+	return f.LookupSelfWithContextFn(ctx)
 }
 
-// An RequestFn operates on the supplied Request. You might use an RequestFn to
-// test or update the contents of an Request.
-type RequestFn func(req *vault.Request) error
+type MockSetTokenFn func(v string)
 
-func NewMockRawRequestWithContextFn(res *vault.Response, err error, ofn ...RequestFn) MockRawRequestWithContextFn {
-	return func(_ context.Context, r *vault.Request) (*vault.Response, error) {
-		for _, fn := range ofn {
-			if err := fn(r); err != nil {
-				return res, err
-			}
-		}
-		return res, err
-	}
-}
+type MockTokenFn func() string
+
+type MockClearTokenFn func()
+
+type MockSetNamespaceFn func(namespace string)
+
+type MockAddHeaderFn func(key, value string)
 
 type VaultListResponse struct {
 	Metadata *vault.Response
 	Data     *vault.Response
 }
 
-func NewMockRawRequestListWithContextFn(res map[string]VaultListResponse, err error) MockRawRequestWithContextFn {
-	return func(_ context.Context, r *vault.Request) (*vault.Response, error) {
-		pathList := strings.Split(r.URL.Path, "/")
-		path := "default"
-		if pathList[4] != "" {
-			path = strings.Join(pathList[4:], "/")
-		}
-		if strings.Contains(r.URL.Path, "metadata") {
-			resp := res[path].Metadata
-			return resp, err
-		}
-		resp := res[path].Data
-		return resp, err
-	}
-}
-
 func NewSetTokenFn(ofn ...func(v string)) MockSetTokenFn {
 	return func(v string) {
 		for _, fn := range ofn {
@@ -116,21 +115,48 @@ func NewAddHeaderFn() MockAddHeaderFn {
 }
 
 type VaultClient struct {
-	MockNewRequest            MockNewRequestFn
-	MockRawRequestWithContext MockRawRequestWithContextFn
-	MockSetToken              MockSetTokenFn
-	MockToken                 MockTokenFn
-	MockClearToken            MockClearTokenFn
-	MockSetNamespace          MockSetNamespaceFn
-	MockAddHeader             MockAddHeaderFn
+	MockLogical      Logical
+	MockAuth         Auth
+	MockAuthToken    Token
+	MockSetToken     MockSetTokenFn
+	MockToken        MockTokenFn
+	MockClearToken   MockClearTokenFn
+	MockSetNamespace MockSetNamespaceFn
+	MockAddHeader    MockAddHeaderFn
+}
+
+func (c *VaultClient) Logical() Logical {
+	return c.MockLogical
+}
+
+func NewVaultLogical() Logical {
+	logical := Logical{
+		ReadWithDataWithContextFn: func(ctx context.Context, path string, data map[string][]string) (*vault.Secret, error) {
+			return nil, nil
+		},
+		ListWithContextFn: func(ctx context.Context, path string) (*vault.Secret, error) {
+			return nil, nil
+		},
+		WriteWithContextFn: func(ctx context.Context, path string, data map[string]interface{}) (*vault.Secret, error) {
+			return nil, nil
+		},
+	}
+	return logical
 }
-
-func (c *VaultClient) NewRequest(method, requestPath string) *vault.Request {
-	return c.MockNewRequest(method, requestPath)
+func (c *VaultClient) Auth() Auth {
+	return c.MockAuth
 }
 
-func (c *VaultClient) RawRequestWithContext(ctx context.Context, r *vault.Request) (*vault.Response, error) {
-	return c.MockRawRequestWithContext(ctx, r)
+func NewVaultAuth() Auth {
+	auth := Auth{
+		LoginFn: func(ctx context.Context, authMethod vault.AuthMethod) (*vault.Secret, error) {
+			return nil, nil
+		},
+	}
+	return auth
+}
+func (c *VaultClient) AuthToken() Token {
+	return c.MockAuthToken
 }
 
 func (c *VaultClient) SetToken(v string) {

+ 182 - 207
pkg/provider/vault/vault.go

@@ -28,6 +28,9 @@ import (
 
 	"github.com/go-logr/logr"
 	vault "github.com/hashicorp/vault/api"
+	approle "github.com/hashicorp/vault/api/auth/approle"
+	authkubernetes "github.com/hashicorp/vault/api/auth/kubernetes"
+	authldap "github.com/hashicorp/vault/api/auth/ldap"
 	"github.com/tidwall/gjson"
 	authenticationv1 "k8s.io/api/authentication/v1"
 	corev1 "k8s.io/api/core/v1"
@@ -65,9 +68,7 @@ const (
 	errSecretFormat         = "secret data not in expected format"
 	errUnexpectedKey        = "unexpected key in data: %s"
 	errVaultToken           = "cannot parse Vault authentication token: %w"
-	errVaultReqParams       = "cannot set Vault request parameters: %w"
 	errVaultRequest         = "error from Vault request: %w"
-	errVaultResponse        = "cannot parse Vault response: %w"
 	errServiceAccount       = "cannot read Kubernetes service account token from file system: %w"
 	errJwtNoTokenSource     = "neither `secretRef` nor `kubernetesServiceAccountToken` was supplied as token source for jwt authentication"
 	errUnsupportedKvVersion = "cannot perform find operations with kv version v1"
@@ -107,22 +108,84 @@ const (
 var _ esv1beta1.SecretsClient = &client{}
 var _ esv1beta1.Provider = &connector{}
 
+type Auth interface {
+	Login(ctx context.Context, authMethod vault.AuthMethod) (*vault.Secret, error)
+}
+
+type Token interface {
+	RevokeSelfWithContext(ctx context.Context, token string) error
+	LookupSelfWithContext(ctx context.Context) (*vault.Secret, error)
+}
+
+type Logical interface {
+	ReadWithDataWithContext(ctx context.Context, path string, data map[string][]string) (*vault.Secret, error)
+	ListWithContext(ctx context.Context, path string) (*vault.Secret, error)
+	WriteWithContext(ctx context.Context, path string, data map[string]interface{}) (*vault.Secret, error)
+}
+
 type Client interface {
-	NewRequest(method, requestPath string) *vault.Request
-	RawRequestWithContext(ctx context.Context, r *vault.Request) (*vault.Response, error)
 	SetToken(v string)
 	Token() string
 	ClearToken()
+	Auth() Auth
+	Logical() Logical
+	AuthToken() Token
 	SetNamespace(namespace string)
 	AddHeader(key, value string)
 }
 
+type VClient struct {
+	setToken     func(v string)
+	token        func() string
+	clearToken   func()
+	auth         Auth
+	logical      Logical
+	authToken    Token
+	setNamespace func(namespace string)
+	addHeader    func(key, value string)
+}
+
+func (v VClient) AddHeader(key, value string) {
+	v.addHeader(key, value)
+}
+
+func (v VClient) SetNamespace(namespace string) {
+	v.setNamespace(namespace)
+}
+
+func (v VClient) ClearToken() {
+	v.clearToken()
+}
+
+func (v VClient) Token() string {
+	return v.token()
+}
+
+func (v VClient) SetToken(token string) {
+	v.setToken(token)
+}
+
+func (v VClient) Auth() Auth {
+	return v.auth
+}
+
+func (v VClient) AuthToken() Token {
+	return v.authToken
+}
+
+func (v VClient) Logical() Logical {
+	return v.logical
+}
+
 type client struct {
 	kube      kclient.Client
-	corev1    typedcorev1.CoreV1Interface
 	store     *esv1beta1.VaultProvider
 	log       logr.Logger
+	corev1    typedcorev1.CoreV1Interface
 	client    Client
+	auth      Auth
+	logical   Logical
+	token     Token
 	namespace string
 	storeKind string
 }
@@ -136,7 +199,24 @@ func init() {
 }
 
 func newVaultClient(c *vault.Config) (Client, error) {
-	return vault.NewClient(c)
+	cl, err := vault.NewClient(c)
+	if err != nil {
+		return nil, err
+	}
+	auth := cl.Auth()
+	logical := cl.Logical()
+	token := cl.Auth().Token()
+	out := VClient{
+		setToken:     cl.SetToken,
+		token:        cl.Token,
+		clearToken:   cl.ClearToken,
+		auth:         auth,
+		authToken:    token,
+		logical:      logical,
+		setNamespace: cl.SetNamespace,
+		addHeader:    cl.AddHeader,
+	}
+	return out, nil
 }
 
 type connector struct {
@@ -191,13 +271,15 @@ func (c *connector) newClient(ctx context.Context, store esv1beta1.GenericStore,
 	if vaultSpec.ReadYourWrites && vaultSpec.ForwardInconsistent {
 		client.AddHeader("X-Vault-Inconsistent", "forward-active-node")
 	}
+	vStore.client = client
+	vStore.auth = client.Auth()
+	vStore.logical = client.Logical()
+	vStore.token = client.AuthToken()
 
-	if err := vStore.setAuth(ctx, client, cfg); err != nil {
+	if err := vStore.setAuth(ctx, cfg); err != nil {
 		return nil, err
 	}
 
-	vStore.client = client
-
 	return vStore, nil
 }
 
@@ -340,16 +422,10 @@ func (v *client) listSecrets(ctx context.Context, path string) ([]string, error)
 	if err != nil {
 		return nil, err
 	}
-	r := v.client.NewRequest(http.MethodGet, url)
-	r.Params.Set("list", "true")
-	resp, err := v.client.RawRequestWithContext(ctx, r)
+	secret, err := v.logical.ListWithContext(ctx, url)
 	if err != nil {
 		return nil, fmt.Errorf(errReadSecret, err)
 	}
-	secret, parseErr := vault.ParseSecret(resp.Body)
-	if parseErr != nil {
-		return nil, parseErr
-	}
 	t, ok := secret.Data["keys"]
 	if !ok {
 		return nil, nil
@@ -381,15 +457,10 @@ func (v *client) readSecretMetadata(ctx context.Context, path string) (map[strin
 	if err != nil {
 		return nil, err
 	}
-	r := v.client.NewRequest(http.MethodGet, url)
-	resp, err := v.client.RawRequestWithContext(ctx, r)
+	secret, err := v.logical.ReadWithDataWithContext(ctx, url, nil)
 	if err != nil {
 		return nil, fmt.Errorf(errReadSecret, err)
 	}
-	secret, parseErr := vault.ParseSecret(resp.Body)
-	if parseErr != nil {
-		return nil, parseErr
-	}
 	t, ok := secret.Data["custom_metadata"]
 	if !ok {
 		return nil, nil
@@ -490,18 +561,23 @@ func getTypedKey(data map[string]interface{}, key string) ([]byte, error) {
 func (v *client) Close(ctx context.Context) error {
 	// Revoke the token if we have one set and it wasn't sourced from a TokenSecretRef
 	if v.client.Token() != "" && v.store.Auth.TokenSecretRef == nil {
-		req := v.client.NewRequest(http.MethodPost, "/v1/auth/token/revoke-self")
-		_, err := v.client.RawRequestWithContext(ctx, req)
+		revoke, err := checkToken(ctx, v)
 		if err != nil {
 			return fmt.Errorf(errVaultRevokeToken, err)
 		}
-		v.client.ClearToken()
+		if revoke {
+			err = v.token.RevokeSelfWithContext(ctx, v.client.Token())
+			if err != nil {
+				return fmt.Errorf(errVaultRevokeToken, err)
+			}
+			v.client.ClearToken()
+		}
 	}
 	return nil
 }
 
 func (v *client) Validate() error {
-	err := checkToken(context.Background(), v)
+	_, err := checkToken(context.Background(), v)
 	if err != nil {
 		return fmt.Errorf(errInvalidCredentials, err)
 	}
@@ -515,9 +591,9 @@ func (v *client) buildMetadataPath(path string) (string, error) {
 	}
 	if v.store.Path == nil {
 		path = strings.Replace(path, "data", "metadata", 1)
-		url = fmt.Sprintf("/v1/%s", path)
+		url = path
 	} else {
-		url = fmt.Sprintf("/v1/%s/metadata/%s", *v.store.Path, path)
+		url = fmt.Sprintf("%s/metadata/%s", *v.store.Path, path)
 	}
 	return url, nil
 }
@@ -554,21 +630,15 @@ func (v *client) readSecret(ctx context.Context, path, version string) (map[stri
 	// path formated according to vault docs for v1 and v2 API
 	// v1: https://www.vaultproject.io/api-docs/secret/kv/kv-v1#read-secret
 	// v2: https://www.vaultproject.io/api/secret/kv/kv-v2#read-secret-version
-	req := v.client.NewRequest(http.MethodGet, fmt.Sprintf("/v1/%s", dataPath))
+	var params map[string][]string
 	if version != "" {
-		req.Params.Set("version", version)
+		params = make(map[string][]string)
+		params["version"] = []string{version}
 	}
-
-	resp, err := v.client.RawRequestWithContext(ctx, req)
+	vaultSecret, err := v.logical.ReadWithDataWithContext(ctx, dataPath, params)
 	if err != nil {
 		return nil, fmt.Errorf(errReadSecret, err)
 	}
-
-	vaultSecret, err := vault.ParseSecret(resp.Body)
-	if err != nil {
-		return nil, err
-	}
-
 	secretData := vaultSecret.Data
 	if v.store.Version == esv1beta1.VaultKVStoreV2 {
 		// Vault KV2 has data embedded within sub-field
@@ -686,33 +756,33 @@ func getCertFromConfigMap(v *client) ([]byte, error) {
 	return []byte(val), nil
 }
 
-func (v *client) setAuth(ctx context.Context, client Client, cfg *vault.Config) error {
-	tokenExists, err := setSecretKeyToken(ctx, v, client)
+func (v *client) setAuth(ctx context.Context, cfg *vault.Config) error {
+	tokenExists, err := setSecretKeyToken(ctx, v)
 	if tokenExists {
 		return err
 	}
 
-	tokenExists, err = setAppRoleToken(ctx, v, client)
+	tokenExists, err = setAppRoleToken(ctx, v)
 	if tokenExists {
 		return err
 	}
 
-	tokenExists, err = setKubernetesAuthToken(ctx, v, client)
+	tokenExists, err = setKubernetesAuthToken(ctx, v)
 	if tokenExists {
 		return err
 	}
 
-	tokenExists, err = setLdapAuthToken(ctx, v, client)
+	tokenExists, err = setLdapAuthToken(ctx, v)
 	if tokenExists {
 		return err
 	}
 
-	tokenExists, err = setJwtAuthToken(ctx, v, client)
+	tokenExists, err = setJwtAuthToken(ctx, v)
 	if tokenExists {
 		return err
 	}
 
-	tokenExists, err = setCertAuthToken(ctx, v, client, cfg)
+	tokenExists, err = setCertAuthToken(ctx, v, cfg)
 	if tokenExists {
 		return err
 	}
@@ -720,79 +790,74 @@ func (v *client) setAuth(ctx context.Context, client Client, cfg *vault.Config)
 	return errors.New(errAuthFormat)
 }
 
-func setAppRoleToken(ctx context.Context, v *client, client Client) (bool, error) {
+func setAppRoleToken(ctx context.Context, v *client) (bool, error) {
 	tokenRef := v.store.Auth.TokenSecretRef
 	if tokenRef != nil {
 		token, err := v.secretKeyRef(ctx, tokenRef)
 		if err != nil {
 			return true, err
 		}
-		client.SetToken(token)
+		v.client.SetToken(token)
 		return true, nil
 	}
 	return false, nil
 }
 
-func setSecretKeyToken(ctx context.Context, v *client, client Client) (bool, error) {
+func setSecretKeyToken(ctx context.Context, v *client) (bool, error) {
 	appRole := v.store.Auth.AppRole
 	if appRole != nil {
-		token, err := v.requestTokenWithAppRoleRef(ctx, client, appRole)
+		err := v.requestTokenWithAppRoleRef(ctx, appRole)
 		if err != nil {
 			return true, err
 		}
-		client.SetToken(token)
 		return true, nil
 	}
 	return false, nil
 }
 
-func setKubernetesAuthToken(ctx context.Context, v *client, client Client) (bool, error) {
+func setKubernetesAuthToken(ctx context.Context, v *client) (bool, error) {
 	kubernetesAuth := v.store.Auth.Kubernetes
 	if kubernetesAuth != nil {
-		token, err := v.requestTokenWithKubernetesAuth(ctx, client, kubernetesAuth)
+		err := v.requestTokenWithKubernetesAuth(ctx, kubernetesAuth)
 		if err != nil {
 			return true, err
 		}
-		client.SetToken(token)
 		return true, nil
 	}
 	return false, nil
 }
 
-func setLdapAuthToken(ctx context.Context, v *client, client Client) (bool, error) {
+func setLdapAuthToken(ctx context.Context, v *client) (bool, error) {
 	ldapAuth := v.store.Auth.Ldap
 	if ldapAuth != nil {
-		token, err := v.requestTokenWithLdapAuth(ctx, client, ldapAuth)
+		err := v.requestTokenWithLdapAuth(ctx, ldapAuth)
 		if err != nil {
 			return true, err
 		}
-		client.SetToken(token)
 		return true, nil
 	}
 	return false, nil
 }
 
-func setJwtAuthToken(ctx context.Context, v *client, client Client) (bool, error) {
+func setJwtAuthToken(ctx context.Context, v *client) (bool, error) {
 	jwtAuth := v.store.Auth.Jwt
 	if jwtAuth != nil {
-		token, err := v.requestTokenWithJwtAuth(ctx, client, jwtAuth)
+		err := v.requestTokenWithJwtAuth(ctx, jwtAuth)
 		if err != nil {
 			return true, err
 		}
-		client.SetToken(token)
 		return true, nil
 	}
 	return false, nil
 }
 
-func setCertAuthToken(ctx context.Context, v *client, client Client, cfg *vault.Config) (bool, error) {
+func setCertAuthToken(ctx context.Context, v *client, cfg *vault.Config) (bool, error) {
 	certAuth := v.store.Auth.Cert
 	if certAuth != nil {
-		token, err := v.requestTokenWithCertAuth(ctx, client, certAuth, cfg)
+		err := v.requestTokenWithCertAuth(ctx, certAuth, cfg)
 		if err != nil {
 			return true, err
 		}
-		client.SetToken(token)
 		return true, nil
 	}
 	return false, nil
@@ -878,101 +943,56 @@ func (v *client) serviceAccountToken(ctx context.Context, serviceAccountRef esme
 }
 
 // checkToken does a lookup and checks if the provided token exists.
-func checkToken(ctx context.Context, vStore *client) error {
+func checkToken(ctx context.Context, vStore *client) (bool, error) {
 	// https://www.vaultproject.io/api-docs/auth/token#lookup-a-token-self
-	req := vStore.client.NewRequest("GET", "/v1/auth/token/lookup-self")
-	_, err := vStore.client.RawRequestWithContext(ctx, req)
-	return err
-}
-
-// appRoleParameters creates the required body for Vault AppRole Auth.
-// Reference - https://www.vaultproject.io/api-docs/auth/approle#login-with-approle
-func appRoleParameters(role, secret string) map[string]string {
-	return map[string]string{
-		"role_id":   role,
-		"secret_id": secret,
+	resp, err := vStore.token.LookupSelfWithContext(ctx)
+	if err != nil {
+		return false, err
 	}
+	t, ok := resp.Data["type"]
+	if !ok {
+		return false, fmt.Errorf("could not assert token type")
+	}
+	tokenType := t.(string)
+	if tokenType == "batch" {
+		return false, nil
+	}
+	return true, nil
 }
 
-func (v *client) requestTokenWithAppRoleRef(ctx context.Context, client Client, appRole *esv1beta1.VaultAppRole) (string, error) {
+func (v *client) requestTokenWithAppRoleRef(ctx context.Context, appRole *esv1beta1.VaultAppRole) error {
 	roleID := strings.TrimSpace(appRole.RoleID)
 
 	secretID, err := v.secretKeyRef(ctx, &appRole.SecretRef)
 	if err != nil {
-		return "", err
+		return err
 	}
-
-	parameters := appRoleParameters(roleID, secretID)
-	url := strings.Join([]string{"/v1", "auth", appRole.Path, "login"}, "/")
-	request := client.NewRequest("POST", url)
-
-	err = request.SetJSONBody(parameters)
+	secret := approle.SecretID{FromString: secretID}
+	appRoleClient, err := approle.NewAppRoleAuth(roleID, &secret, approle.WithMountPath(appRole.Path))
 	if err != nil {
-		return "", fmt.Errorf(errVaultReqParams, err)
-	}
-
-	resp, err := client.RawRequestWithContext(ctx, request)
-	if err != nil {
-		return "", fmt.Errorf(errVaultRequest, err)
-	}
-
-	defer resp.Body.Close()
-
-	vaultResult := vault.Secret{}
-	if err = resp.DecodeJSON(&vaultResult); err != nil {
-		return "", fmt.Errorf(errVaultResponse, err)
+		return err
 	}
-
-	token, err := vaultResult.TokenID()
+	_, err = v.auth.Login(ctx, appRoleClient)
 	if err != nil {
-		return "", fmt.Errorf(errVaultToken, err)
-	}
-
-	return token, nil
-}
-
-// kubeParameters creates the required body for Vault Kubernetes auth.
-// Reference - https://www.vaultproject.io/api/auth/kubernetes#login
-func kubeParameters(role, jwt string) map[string]string {
-	return map[string]string{
-		"role": role,
-		"jwt":  jwt,
+		return err
 	}
+	return nil
 }
 
-func (v *client) requestTokenWithKubernetesAuth(ctx context.Context, client Client, kubernetesAuth *esv1beta1.VaultKubernetesAuth) (string, error) {
+func (v *client) requestTokenWithKubernetesAuth(ctx context.Context, kubernetesAuth *esv1beta1.VaultKubernetesAuth) error {
 	jwtString, err := getJwtString(ctx, v, kubernetesAuth)
 	if err != nil {
-		return "", err
-	}
-
-	parameters := kubeParameters(kubernetesAuth.Role, jwtString)
-	url := strings.Join([]string{"/v1", "auth", kubernetesAuth.Path, "login"}, "/")
-	request := client.NewRequest("POST", url)
-
-	err = request.SetJSONBody(parameters)
-	if err != nil {
-		return "", fmt.Errorf(errVaultReqParams, err)
-	}
-
-	resp, err := client.RawRequestWithContext(ctx, request)
-	if err != nil {
-		return "", fmt.Errorf(errVaultRequest, err)
+		return err
 	}
-
-	defer resp.Body.Close()
-	vaultResult := vault.Secret{}
-	err = resp.DecodeJSON(&vaultResult)
+	k, err := authkubernetes.NewKubernetesAuth(kubernetesAuth.Role, authkubernetes.WithServiceAccountToken(jwtString), authkubernetes.WithMountPath(kubernetesAuth.Path))
 	if err != nil {
-		return "", fmt.Errorf(errVaultResponse, err)
+		return err
 	}
-
-	token, err := vaultResult.TokenID()
+	_, err = v.auth.Login(ctx, k)
 	if err != nil {
-		return "", fmt.Errorf(errVaultToken, err)
+		return err
 	}
-
-	return token, nil
+	return nil
 }
 
 func getJwtString(ctx context.Context, v *client, kubernetesAuth *esv1beta1.VaultKubernetesAuth) (string, error) {
@@ -1008,48 +1028,27 @@ func getJwtString(ctx context.Context, v *client, kubernetesAuth *esv1beta1.Vaul
 	}
 }
 
-func (v *client) requestTokenWithLdapAuth(ctx context.Context, client Client, ldapAuth *esv1beta1.VaultLdapAuth) (string, error) {
+func (v *client) requestTokenWithLdapAuth(ctx context.Context, ldapAuth *esv1beta1.VaultLdapAuth) error {
 	username := strings.TrimSpace(ldapAuth.Username)
 
 	password, err := v.secretKeyRef(ctx, &ldapAuth.SecretRef)
 	if err != nil {
-		return "", err
-	}
-
-	parameters := map[string]string{
-		"password": password,
-	}
-	url := strings.Join([]string{"/v1", "auth", ldapAuth.Path, "login", username}, "/")
-	request := client.NewRequest("POST", url)
-
-	err = request.SetJSONBody(parameters)
-	if err != nil {
-		return "", fmt.Errorf(errVaultReqParams, err)
+		return err
 	}
-
-	resp, err := client.RawRequestWithContext(ctx, request)
+	pass := authldap.Password{FromString: password}
+	l, err := authldap.NewLDAPAuth(username, &pass, authldap.WithMountPath(ldapAuth.Path))
 	if err != nil {
-		return "", fmt.Errorf(errVaultRequest, err)
-	}
-
-	defer resp.Body.Close()
-
-	vaultResult := vault.Secret{}
-	if err = resp.DecodeJSON(&vaultResult); err != nil {
-		return "", fmt.Errorf(errVaultResponse, err)
+		return err
 	}
-
-	token, err := vaultResult.TokenID()
+	_, err = v.auth.Login(ctx, l)
 	if err != nil {
-		return "", fmt.Errorf(errVaultToken, err)
+		return err
 	}
-
-	return token, nil
+	return nil
 }
 
-func (v *client) requestTokenWithJwtAuth(ctx context.Context, client Client, jwtAuth *esv1beta1.VaultJwtAuth) (string, error) {
+func (v *client) requestTokenWithJwtAuth(ctx context.Context, jwtAuth *esv1beta1.VaultJwtAuth) error {
 	role := strings.TrimSpace(jwtAuth.Role)
-
 	var jwt string
 	var err error
 	if jwtAuth.SecretRef != nil {
@@ -1069,80 +1068,56 @@ func (v *client) requestTokenWithJwtAuth(ctx context.Context, client Client, jwt
 		err = fmt.Errorf(errJwtNoTokenSource)
 	}
 	if err != nil {
-		return "", err
+		return err
 	}
 
-	parameters := map[string]string{
+	parameters := map[string]interface{}{
 		"role": role,
 		"jwt":  jwt,
 	}
-	url := strings.Join([]string{"/v1", "auth", jwtAuth.Path, "login"}, "/")
-	request := client.NewRequest("POST", url)
-
-	err = request.SetJSONBody(parameters)
-	if err != nil {
-		return "", fmt.Errorf(errVaultReqParams, err)
-	}
-
-	resp, err := client.RawRequestWithContext(ctx, request)
+	url := strings.Join([]string{"auth", jwtAuth.Path, "login"}, "/")
+	vaultResult, err := v.logical.WriteWithContext(ctx, url, parameters)
 	if err != nil {
-		return "", fmt.Errorf(errVaultRequest, err)
-	}
-
-	defer resp.Body.Close()
-
-	vaultResult := vault.Secret{}
-	if err = resp.DecodeJSON(&vaultResult); err != nil {
-		return "", fmt.Errorf(errVaultResponse, err)
+		return err
 	}
 
 	token, err := vaultResult.TokenID()
 	if err != nil {
-		return "", fmt.Errorf(errVaultToken, err)
+		return fmt.Errorf(errVaultToken, err)
 	}
-
-	return token, nil
+	v.client.SetToken(token)
+	return nil
 }
 
-func (v *client) requestTokenWithCertAuth(ctx context.Context, client Client, certAuth *esv1beta1.VaultCertAuth, cfg *vault.Config) (string, error) {
+func (v *client) requestTokenWithCertAuth(ctx context.Context, certAuth *esv1beta1.VaultCertAuth, cfg *vault.Config) error {
 	clientKey, err := v.secretKeyRef(ctx, &certAuth.SecretRef)
 	if err != nil {
-		return "", err
+		return err
 	}
 
 	clientCert, err := v.secretKeyRef(ctx, &certAuth.ClientCert)
 	if err != nil {
-		return "", err
+		return err
 	}
 
 	cert, err := tls.X509KeyPair([]byte(clientCert), []byte(clientKey))
 	if err != nil {
-		return "", fmt.Errorf(errClientTLSAuth, err)
+		return fmt.Errorf(errClientTLSAuth, err)
 	}
 
 	if transport, ok := cfg.HttpClient.Transport.(*http.Transport); ok {
 		transport.TLSClientConfig.Certificates = []tls.Certificate{cert}
 	}
 
-	url := strings.Join([]string{"/v1", "auth", "cert", "login"}, "/")
-	request := client.NewRequest("POST", url)
-
-	resp, err := client.RawRequestWithContext(ctx, request)
+	url := strings.Join([]string{"auth", "cert", "login"}, "/")
+	vaultResult, err := v.logical.WriteWithContext(ctx, url, nil)
 	if err != nil {
-		return "", fmt.Errorf(errVaultRequest, err)
-	}
-
-	defer resp.Body.Close()
-
-	vaultResult := vault.Secret{}
-	if err = resp.DecodeJSON(&vaultResult); err != nil {
-		return "", fmt.Errorf(errVaultResponse, err)
+		return fmt.Errorf(errVaultRequest, err)
 	}
-
 	token, err := vaultResult.TokenID()
 	if err != nil {
-		return "", fmt.Errorf(errVaultToken, err)
+		return fmt.Errorf(errVaultToken, err)
 	}
-
-	return token, nil
+	v.client.SetToken(token)
+	return nil
 }

+ 142 - 220
pkg/provider/vault/vault_test.go

@@ -15,13 +15,10 @@ limitations under the License.
 package vault
 
 import (
-	"bytes"
 	"context"
-	"encoding/json"
 	"errors"
 	"fmt"
-	"io"
-	"net/http"
+	"strings"
 	"testing"
 
 	"github.com/crossplane/crossplane-runtime/pkg/test"
@@ -171,45 +168,6 @@ func makeSecretStore(tweaks ...secretStoreTweakFn) *esv1beta1.SecretStore {
 	return store
 }
 
-func newVaultResponse(data *vault.Secret) *vault.Response {
-	jsonData, _ := json.Marshal(data)
-	return &vault.Response{
-		Response: &http.Response{
-			Body: io.NopCloser(bytes.NewReader(jsonData)),
-		},
-	}
-}
-
-func newVaultResponseWithData(data map[string]interface{}) *vault.Response {
-	return newVaultResponse(&vault.Secret{
-		Data: data,
-	})
-}
-
-func newVaultResponseWithMetadata(content map[string]interface{}) map[string]fake.VaultListResponse {
-	ans := make(map[string]fake.VaultListResponse)
-	for k, v := range content {
-		t := v.(map[string]interface{})
-		m := t["metadata"].(map[string]interface{})
-		listResponse := fake.VaultListResponse{
-			Data: newVaultResponse(&vault.Secret{
-				Data: t,
-			}),
-			Metadata: newVaultResponse(&vault.Secret{
-				Data: m,
-			}),
-		}
-		ans[k] = listResponse
-	}
-	return ans
-}
-
-func newVaultTokenIDResponse(token string) *vault.Response {
-	return newVaultResponseWithData(map[string]interface{}{
-		"id": token,
-	})
-}
-
 type args struct {
 	newClientFunc func(c *vault.Config) (Client, error)
 	store         esv1beta1.GenericStore
@@ -228,12 +186,25 @@ type testCase struct {
 }
 
 func clientWithLoginMock(c *vault.Config) (Client, error) {
-	return &fake.VaultClient{
-		MockNewRequest: fake.NewMockNewRequestFn(&vault.Request{}),
-		MockRawRequestWithContext: fake.NewMockRawRequestWithContextFn(
-			newVaultTokenIDResponse("test-token"), nil, func(got *vault.Request) error { return nil }),
+	cl := fake.VaultClient{
 		MockSetToken: fake.NewSetTokenFn(),
-	}, nil
+		MockAuth:     fake.NewVaultAuth(),
+		MockLogical:  fake.NewVaultLogical(),
+	}
+	auth := cl.Auth()
+	token := cl.AuthToken()
+	logical := cl.Logical()
+	out := VClient{
+		setToken:     cl.SetToken,
+		token:        cl.Token,
+		clearToken:   cl.ClearToken,
+		auth:         auth,
+		authToken:    token,
+		logical:      logical,
+		setNamespace: cl.SetNamespace,
+		addHeader:    cl.AddHeader,
+	}
+	return out, nil
 }
 
 func kubeMockWithSecretTokenAndServiceAcc(obj kclient.Object) error {
@@ -327,36 +298,6 @@ MIICsTCCAZkCFEJJ4daz5sxkFlzq9n1djLEuG7bmMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNVBAMMCHZh
 				err: fmt.Errorf(errGetKubeSecret, "vault-secret", errBoom),
 			},
 		},
-		"SuccessfulVaultStore": {
-			reason: "Should return a Vault provider successfully",
-			args: args{
-				store: makeSecretStore(),
-				kube: &test.MockClient{
-					MockGet: test.NewMockGetFn(nil, kubeMockWithSecretTokenAndServiceAcc),
-				},
-				newClientFunc: func(c *vault.Config) (Client, error) {
-					return &fake.VaultClient{
-						MockNewRequest: fake.NewMockNewRequestFn(&vault.Request{}),
-						MockRawRequestWithContext: fake.NewMockRawRequestWithContextFn(
-							newVaultTokenIDResponse("test-token"), nil, func(got *vault.Request) error {
-								kubeRole := makeValidSecretStore().Spec.Provider.Vault.Auth.Kubernetes.Role
-								want := kubeParameters(kubeRole, string(secretData))
-								if diff := cmp.Diff(want, got.Obj); diff != "" {
-									t.Errorf("RawRequestWithContext(...): -want, +got:\n%s", diff)
-								}
-
-								return nil
-							}),
-						MockSetToken:   fake.NewSetTokenFn(),
-						MockToken:      fake.NewTokenFn(""),
-						MockClearToken: fake.NewClearTokenFn(),
-					}, nil
-				},
-			},
-			want: want{
-				err: nil,
-			},
-		},
 		"SuccessfulVaultStoreWithCertAuth": {
 			reason: "Should return a Vault provider successfully",
 			args: args{
@@ -592,11 +533,11 @@ func TestGetSecret(t *testing.T) {
 	}
 
 	type args struct {
-		store   *esv1beta1.VaultProvider
-		kube    kclient.Client
-		vClient Client
-		ns      string
-		data    esv1beta1.ExternalSecretDataRemoteRef
+		store    *esv1beta1.VaultProvider
+		kube     kclient.Client
+		vLogical Logical
+		ns       string
+		data     esv1beta1.ExternalSecretDataRemoteRef
 	}
 
 	type want struct {
@@ -616,11 +557,8 @@ func TestGetSecret(t *testing.T) {
 				data: esv1beta1.ExternalSecretDataRemoteRef{
 					Property: "access_key",
 				},
-				vClient: &fake.VaultClient{
-					MockNewRequest: fake.NewMockNewRequestFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestWithContextFn(
-						newVaultResponseWithData(secret), nil,
-					),
+				vLogical: &fake.Logical{
+					ReadWithDataWithContextFn: fake.NewReadWithContextFn(secret, nil),
 				},
 			},
 			want: want{
@@ -635,11 +573,8 @@ func TestGetSecret(t *testing.T) {
 				data: esv1beta1.ExternalSecretDataRemoteRef{
 					Property: "access_key",
 				},
-				vClient: &fake.VaultClient{
-					MockNewRequest: fake.NewMockNewRequestFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestWithContextFn(
-						newVaultResponseWithData(secretWithNilVal), nil,
-					),
+				vLogical: &fake.Logical{
+					ReadWithDataWithContextFn: fake.NewReadWithContextFn(secretWithNilVal, nil),
 				},
 			},
 			want: want{
@@ -652,11 +587,8 @@ func TestGetSecret(t *testing.T) {
 			args: args{
 				store: makeValidSecretStoreWithVersion(esv1beta1.VaultKVStoreV1).Spec.Provider.Vault,
 				data:  esv1beta1.ExternalSecretDataRemoteRef{},
-				vClient: &fake.VaultClient{
-					MockNewRequest: fake.NewMockNewRequestFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestWithContextFn(
-						newVaultResponseWithData(secret), nil,
-					),
+				vLogical: &fake.Logical{
+					ReadWithDataWithContextFn: fake.NewReadWithContextFn(secret, nil),
 				},
 			},
 			want: want{
@@ -671,11 +603,8 @@ func TestGetSecret(t *testing.T) {
 				data: esv1beta1.ExternalSecretDataRemoteRef{
 					Property: "nested.foo",
 				},
-				vClient: &fake.VaultClient{
-					MockNewRequest: fake.NewMockNewRequestFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestWithContextFn(
-						newVaultResponseWithData(secretWithNestedVal), nil,
-					),
+				vLogical: &fake.Logical{
+					ReadWithDataWithContextFn: fake.NewReadWithContextFn(secretWithNestedVal, nil),
 				},
 			},
 			want: want{
@@ -691,11 +620,8 @@ func TestGetSecret(t *testing.T) {
 					//
 					Property: "nested.bar",
 				},
-				vClient: &fake.VaultClient{
-					MockNewRequest: fake.NewMockNewRequestFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestWithContextFn(
-						newVaultResponseWithData(secretWithNestedVal), nil,
-					),
+				vLogical: &fake.Logical{
+					ReadWithDataWithContextFn: fake.NewReadWithContextFn(secretWithNestedVal, nil),
 				},
 			},
 			want: want{
@@ -710,11 +636,8 @@ func TestGetSecret(t *testing.T) {
 				data: esv1beta1.ExternalSecretDataRemoteRef{
 					Property: "nop.doesnt.exist",
 				},
-				vClient: &fake.VaultClient{
-					MockNewRequest: fake.NewMockNewRequestFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestWithContextFn(
-						newVaultResponseWithData(secretWithNestedVal), nil,
-					),
+				vLogical: &fake.Logical{
+					ReadWithDataWithContextFn: fake.NewReadWithContextFn(secretWithNestedVal, nil),
 				},
 			},
 			want: want{
@@ -725,9 +648,8 @@ func TestGetSecret(t *testing.T) {
 			reason: "Should return error if vault client fails to read secret.",
 			args: args{
 				store: makeSecretStore().Spec.Provider.Vault,
-				vClient: &fake.VaultClient{
-					MockNewRequest:            fake.NewMockNewRequestFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestWithContextFn(nil, errBoom),
+				vLogical: &fake.Logical{
+					ReadWithDataWithContextFn: fake.NewReadWithContextFn(nil, errBoom),
 				},
 			},
 			want: want{
@@ -740,7 +662,7 @@ func TestGetSecret(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			vStore := &client{
 				kube:      tc.args.kube,
-				client:    tc.args.vClient,
+				logical:   tc.args.vLogical,
 				store:     tc.args.store,
 				namespace: tc.args.ns,
 			}
@@ -788,7 +710,7 @@ func TestGetSecretMap(t *testing.T) {
 	type args struct {
 		store   *esv1beta1.VaultProvider
 		kube    kclient.Client
-		vClient Client
+		vClient Logical
 		ns      string
 		data    esv1beta1.ExternalSecretDataRemoteRef
 	}
@@ -807,11 +729,8 @@ func TestGetSecretMap(t *testing.T) {
 			reason: "Should map the secret even if it has a nil value",
 			args: args{
 				store: makeValidSecretStoreWithVersion(esv1beta1.VaultKVStoreV1).Spec.Provider.Vault,
-				vClient: &fake.VaultClient{
-					MockNewRequest: fake.NewMockNewRequestFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestWithContextFn(
-						newVaultResponseWithData(secret), nil,
-					),
+				vClient: &fake.Logical{
+					ReadWithDataWithContextFn: fake.NewReadWithContextFn(secret, nil),
 				},
 			},
 			want: want{
@@ -826,15 +745,10 @@ func TestGetSecretMap(t *testing.T) {
 			reason: "Should map the secret even if it has a nil value",
 			args: args{
 				store: makeValidSecretStoreWithVersion(esv1beta1.VaultKVStoreV2).Spec.Provider.Vault,
-				vClient: &fake.VaultClient{
-					MockNewRequest: fake.NewMockNewRequestFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestWithContextFn(
-						newVaultResponseWithData(
-							map[string]interface{}{
-								"data": secret,
-							},
-						), nil,
-					),
+				vClient: &fake.Logical{
+					ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]interface{}{
+						"data": secret,
+					}, nil),
 				},
 			},
 			want: want{
@@ -849,11 +763,8 @@ func TestGetSecretMap(t *testing.T) {
 			reason: "Should map the secret even if it has a nil value",
 			args: args{
 				store: makeValidSecretStoreWithVersion(esv1beta1.VaultKVStoreV1).Spec.Provider.Vault,
-				vClient: &fake.VaultClient{
-					MockNewRequest: fake.NewMockNewRequestFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestWithContextFn(
-						newVaultResponseWithData(secretWithNilVal), nil,
-					),
+				vClient: &fake.Logical{
+					ReadWithDataWithContextFn: fake.NewReadWithContextFn(secretWithNilVal, nil),
 				},
 			},
 			want: want{
@@ -869,15 +780,9 @@ func TestGetSecretMap(t *testing.T) {
 			reason: "Should map the secret even if it has a nil value",
 			args: args{
 				store: makeValidSecretStoreWithVersion(esv1beta1.VaultKVStoreV2).Spec.Provider.Vault,
-				vClient: &fake.VaultClient{
-					MockNewRequest: fake.NewMockNewRequestFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestWithContextFn(
-						newVaultResponseWithData(
-							map[string]interface{}{
-								"data": secretWithNilVal,
-							},
-						), nil,
-					),
+				vClient: &fake.Logical{
+					ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]interface{}{
+						"data": secretWithNilVal}, nil),
 				},
 			},
 			want: want{
@@ -893,15 +798,9 @@ func TestGetSecretMap(t *testing.T) {
 			reason: "Should map the secret even if it has other types",
 			args: args{
 				store: makeValidSecretStoreWithVersion(esv1beta1.VaultKVStoreV2).Spec.Provider.Vault,
-				vClient: &fake.VaultClient{
-					MockNewRequest: fake.NewMockNewRequestFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestWithContextFn(
-						newVaultResponseWithData(
-							map[string]interface{}{
-								"data": secretWithTypes,
-							},
-						), nil,
-					),
+				vClient: &fake.Logical{
+					ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]interface{}{
+						"data": secretWithTypes}, nil),
 				},
 			},
 			want: want{
@@ -923,15 +822,9 @@ func TestGetSecretMap(t *testing.T) {
 				data: esv1beta1.ExternalSecretDataRemoteRef{
 					Property: "nested",
 				},
-				vClient: &fake.VaultClient{
-					MockNewRequest: fake.NewMockNewRequestFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestWithContextFn(
-						newVaultResponseWithData(
-							map[string]interface{}{
-								"data": secretWithNestedVal,
-							},
-						), nil,
-					),
+				vClient: &fake.Logical{
+					ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]interface{}{
+						"data": secretWithNestedVal}, nil),
 				},
 			},
 			want: want{
@@ -948,15 +841,9 @@ func TestGetSecretMap(t *testing.T) {
 				data: esv1beta1.ExternalSecretDataRemoteRef{
 					Property: "nested.foo",
 				},
-				vClient: &fake.VaultClient{
-					MockNewRequest: fake.NewMockNewRequestFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestWithContextFn(
-						newVaultResponseWithData(
-							map[string]interface{}{
-								"data": secretWithNestedVal,
-							},
-						), nil,
-					),
+				vClient: &fake.Logical{
+					ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]interface{}{
+						"data": secretWithNestedVal}, nil),
 				},
 			},
 			want: want{
@@ -971,9 +858,8 @@ func TestGetSecretMap(t *testing.T) {
 			reason: "Should return error if vault client fails to read secret.",
 			args: args{
 				store: makeSecretStore().Spec.Provider.Vault,
-				vClient: &fake.VaultClient{
-					MockNewRequest:            fake.NewMockNewRequestFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestWithContextFn(nil, errBoom),
+				vClient: &fake.Logical{
+					ReadWithDataWithContextFn: fake.NewReadWithContextFn(nil, errBoom),
 				},
 			},
 			want: want{
@@ -986,7 +872,7 @@ func TestGetSecretMap(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			vStore := &client{
 				kube:      tc.args.kube,
-				client:    tc.args.vClient,
+				logical:   tc.args.vClient,
 				store:     tc.args.store,
 				namespace: tc.args.ns,
 			}
@@ -1001,6 +887,50 @@ func TestGetSecretMap(t *testing.T) {
 	}
 }
 
+func newListWithContextFn(secrets map[string]interface{}) func(ctx context.Context, path string) (*vault.Secret, error) {
+	return func(ctx context.Context, path string) (*vault.Secret, error) {
+		path = strings.TrimPrefix(path, "secret/metadata/")
+		if path == "" {
+			path = "default"
+		}
+		data, ok := secrets[path]
+		if !ok {
+			return nil, errors.New("Secret not found")
+		}
+		meta := data.(map[string]interface{})
+		ans := meta["metadata"].(map[string]interface{})
+		secret := &vault.Secret{
+			Data: map[string]interface{}{
+				"keys": ans["keys"],
+			},
+		}
+		return secret, nil
+	}
+}
+
+func newReadtWithContextFn(secrets map[string]interface{}) func(ctx context.Context, path string, data map[string][]string) (*vault.Secret, error) {
+	return func(ctx context.Context, path string, d map[string][]string) (*vault.Secret, error) {
+		path = strings.TrimPrefix(path, "secret/data/")
+		path = strings.TrimPrefix(path, "secret/metadata/")
+		if path == "" {
+			path = "default"
+		}
+		data, ok := secrets[path]
+		if !ok {
+			return nil, errors.New("Secret not found")
+		}
+		meta := data.(map[string]interface{})
+		metadata := meta["metadata"].(map[string]interface{})
+		content := map[string]interface{}{
+			"data":            meta["data"],
+			"custom_metadata": metadata["custom_metadata"],
+		}
+		secret := &vault.Secret{
+			Data: content,
+		}
+		return secret, nil
+	}
+}
 func TestGetAllSecrets(t *testing.T) {
 	secret1Bytes := []byte("{\"access_key\":\"access_key\",\"access_secret\":\"access_secret\"}")
 	secret2Bytes := []byte("{\"access_key\":\"access_key2\",\"access_secret\":\"access_secret2\"}")
@@ -1010,66 +940,66 @@ func TestGetAllSecrets(t *testing.T) {
 	path := "path"
 	secret := map[string]interface{}{
 		"secret1": map[string]interface{}{
+			"metadata": map[string]interface{}{
+				"custom_metadata": map[string]interface{}{
+					"foo": "bar",
+				},
+			},
 			"data": map[string]interface{}{
 				"access_key":    "access_key",
 				"access_secret": "access_secret",
 			},
+		},
+		"secret2": map[string]interface{}{
 			"metadata": map[string]interface{}{
 				"custom_metadata": map[string]interface{}{
-					"foo": "bar",
+					"foo": "baz",
 				},
 			},
-		},
-		"secret2": map[string]interface{}{
 			"data": map[string]interface{}{
 				"access_key":    "access_key2",
 				"access_secret": "access_secret2",
 			},
+		},
+		"tag": map[string]interface{}{
 			"metadata": map[string]interface{}{
 				"custom_metadata": map[string]interface{}{
 					"foo": "baz",
 				},
 			},
-		},
-		"tag": map[string]interface{}{
 			"data": map[string]interface{}{
 				"access_key":    "unfetched",
 				"access_secret": "unfetched",
 			},
+		},
+		"path/1": map[string]interface{}{
 			"metadata": map[string]interface{}{
 				"custom_metadata": map[string]interface{}{
-					"foo": "baz",
+					"foo": "path",
 				},
 			},
-		},
-		"path/1": map[string]interface{}{
 			"data": map[string]interface{}{
 				"access_key":    "path1",
 				"access_secret": "path1",
 			},
+		},
+		"path/2": map[string]interface{}{
 			"metadata": map[string]interface{}{
 				"custom_metadata": map[string]interface{}{
 					"foo": "path",
 				},
 			},
-		},
-		"path/2": map[string]interface{}{
 			"data": map[string]interface{}{
 				"access_key":    "path2",
 				"access_secret": "path2",
 			},
-			"metadata": map[string]interface{}{
-				"custom_metadata": map[string]interface{}{
-					"foo": "path",
-				},
-			},
 		},
 		"default": map[string]interface{}{
 			"data": map[string]interface{}{
 				"empty": "true",
 			},
 			"metadata": map[string]interface{}{
-				"keys": []string{"secret1", "secret2", "tag", "path/"},
+				"keys": []interface{}{"secret1", "secret2", "tag", "path/"},
 			},
 		},
 		"path/": map[string]interface{}{
@@ -1077,16 +1007,16 @@ func TestGetAllSecrets(t *testing.T) {
 				"empty": "true",
 			},
 			"metadata": map[string]interface{}{
-				"keys": []string{"1", "2"},
+				"keys": []interface{}{"1", "2"},
 			},
 		},
 	}
 	type args struct {
-		store   *esv1beta1.VaultProvider
-		kube    kclient.Client
-		vClient Client
-		ns      string
-		data    esv1beta1.ExternalSecretFind
+		store    *esv1beta1.VaultProvider
+		kube     kclient.Client
+		vLogical Logical
+		ns       string
+		data     esv1beta1.ExternalSecretFind
 	}
 
 	type want struct {
@@ -1103,11 +1033,9 @@ func TestGetAllSecrets(t *testing.T) {
 			reason: "should map multiple secrets matching name",
 			args: args{
 				store: makeValidSecretStoreWithVersion(esv1beta1.VaultKVStoreV2).Spec.Provider.Vault,
-				vClient: &fake.VaultClient{
-					MockNewRequest: fake.NewMockNewRequestListFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestListWithContextFn(
-						newVaultResponseWithMetadata(secret), nil,
-					),
+				vLogical: &fake.Logical{
+					ListWithContextFn:         newListWithContextFn(secret),
+					ReadWithDataWithContextFn: newReadtWithContextFn(secret),
 				},
 				data: esv1beta1.ExternalSecretFind{
 					Name: &esv1beta1.FindName{
@@ -1127,11 +1055,9 @@ func TestGetAllSecrets(t *testing.T) {
 			reason: "should map multiple secrets matching tags",
 			args: args{
 				store: makeValidSecretStoreWithVersion(esv1beta1.VaultKVStoreV2).Spec.Provider.Vault,
-				vClient: &fake.VaultClient{
-					MockNewRequest: fake.NewMockNewRequestListFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestListWithContextFn(
-						newVaultResponseWithMetadata(secret), nil,
-					),
+				vLogical: &fake.Logical{
+					ListWithContextFn:         newListWithContextFn(secret),
+					ReadWithDataWithContextFn: newReadtWithContextFn(secret),
 				},
 				data: esv1beta1.ExternalSecretFind{
 					Tags: map[string]string{
@@ -1151,11 +1077,9 @@ func TestGetAllSecrets(t *testing.T) {
 			reason: "should filter secrets based on path",
 			args: args{
 				store: makeValidSecretStoreWithVersion(esv1beta1.VaultKVStoreV2).Spec.Provider.Vault,
-				vClient: &fake.VaultClient{
-					MockNewRequest: fake.NewMockNewRequestListFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestListWithContextFn(
-						newVaultResponseWithMetadata(secret), nil,
-					),
+				vLogical: &fake.Logical{
+					ListWithContextFn:         newListWithContextFn(secret),
+					ReadWithDataWithContextFn: newReadtWithContextFn(secret),
 				},
 				data: esv1beta1.ExternalSecretFind{
 					Path: &path,
@@ -1176,11 +1100,9 @@ func TestGetAllSecrets(t *testing.T) {
 			reason: "should not work if using kv1 store",
 			args: args{
 				store: makeValidSecretStoreWithVersion(esv1beta1.VaultKVStoreV1).Spec.Provider.Vault,
-				vClient: &fake.VaultClient{
-					MockNewRequest: fake.NewMockNewRequestListFn(&vault.Request{}),
-					MockRawRequestWithContext: fake.NewMockRawRequestListWithContextFn(
-						newVaultResponseWithMetadata(secret), nil,
-					),
+				vLogical: &fake.Logical{
+					ListWithContextFn:         newListWithContextFn(secret),
+					ReadWithDataWithContextFn: newReadtWithContextFn(secret),
 				},
 				data: esv1beta1.ExternalSecretFind{
 					Tags: map[string]string{
@@ -1198,7 +1120,7 @@ func TestGetAllSecrets(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			vStore := &client{
 				kube:      tc.args.kube,
-				client:    tc.args.vClient,
+				logical:   tc.args.vLogical,
 				store:     tc.args.store,
 				namespace: tc.args.ns,
 			}