1
0
Fork 0
mirror of https://github.com/external-secrets/external-secrets.git synced 2024-12-14 11:57:59 +00:00

feat: make cache generic, refactor feature flags (#1640)

Signed-off-by: Moritz Johner <beller.moritz@googlemail.com>

Signed-off-by: Moritz Johner <beller.moritz@googlemail.com>
This commit is contained in:
Moritz Johner 2023-01-19 17:25:47 +01:00 committed by GitHub
parent 769efdc391
commit 5ef3b23a68
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 389 additions and 180 deletions

View file

@ -39,8 +39,7 @@ import (
"github.com/external-secrets/external-secrets/pkg/controllers/externalsecret"
"github.com/external-secrets/external-secrets/pkg/controllers/pushsecret"
"github.com/external-secrets/external-secrets/pkg/controllers/secretstore"
awsauth "github.com/external-secrets/external-secrets/pkg/provider/aws/auth"
"github.com/external-secrets/external-secrets/pkg/provider/vault"
"github.com/external-secrets/external-secrets/pkg/feature"
)
var (
@ -72,9 +71,6 @@ var (
crdRequeueInterval time.Duration
certCheckInterval time.Duration
certLookaheadInterval time.Duration
enableAWSSession bool
enableVaultTokenCache bool
vaultTokenCacheSize int
tlsCiphers string
tlsMinVersion string
)
@ -205,19 +201,19 @@ var rootCmd = &cobra.Command{
os.Exit(1)
}
}
if enableAWSSession {
awsauth.EnableCache = true
fs := feature.Features()
for _, f := range fs {
if f.Initialize == nil {
continue
}
if enableVaultTokenCache {
vault.EnableCache = true
vault.VaultClientCache.Size = vaultTokenCacheSize
f.Initialize()
}
setupLog.Info("starting manager")
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
setupLog.Error(err, "problem running manager")
os.Exit(1)
}
},
}
@ -244,7 +240,8 @@ func init() {
rootCmd.Flags().BoolVar(&enableConfigMapsCache, "enable-configmaps-caching", false, "Enable secrets caching for external-secrets pod.")
rootCmd.Flags().DurationVar(&storeRequeueInterval, "store-requeue-interval", time.Minute*5, "Default Time duration between reconciling (Cluster)SecretStores")
rootCmd.Flags().BoolVar(&enableFloodGate, "enable-flood-gate", true, "Enable flood gate. External secret will be reconciled only if the ClusterStore or Store have an healthy or unknown state.")
rootCmd.Flags().BoolVar(&enableAWSSession, "experimental-enable-aws-session-cache", false, "Enable experimental AWS session cache. External secret will reuse the AWS session without creating a new one on each request.")
rootCmd.Flags().BoolVar(&enableVaultTokenCache, "experimental-enable-vault-token-cache", false, "Enable experimental Vault token cache. External secrets will reuse the Vault token without creating a new one on each request.")
rootCmd.Flags().IntVar(&vaultTokenCacheSize, "experimental-vault-token-cache-size", 100, "Maximum size of Vault token cache. Only used if --experimental-enable-vault-token-cache is set.")
fs := feature.Features()
for _, f := range fs {
rootCmd.Flags().AddFlagSet(f.Flags)
}
}

View file

@ -57,6 +57,22 @@ func NewESO(mutators ...MutationFunc) *ESO {
Key: installCRDsVar,
Value: "false",
},
{
Key: "concurrent",
Value: "100",
},
{
Key: "extraArgs.experimental-enable-vault-token-cache",
Value: "true",
},
{
Key: "extraArgs.experimental-enable-aws-session-cache",
Value: "true",
},
{
Key: "extraArgs.experimental-vault-token-cache-size",
Value: "10",
},
},
},
}

View file

@ -20,11 +20,16 @@ import (
"encoding/json"
"time"
//nolint
. "github.com/onsi/gomega"
v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"github.com/external-secrets/external-secrets-e2e/framework/log"
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
)
@ -45,6 +50,56 @@ func (f *Framework) WaitForSecretValue(namespace, name string, expected *v1.Secr
return secret, err
}
func (f *Framework) printESDebugLogs(esName, esNamespace string) {
// fetch es and print status condition
var es esv1beta1.ExternalSecret
err := f.CRClient.Get(context.Background(), types.NamespacedName{
Name: esName,
Namespace: esNamespace,
}, &es)
Expect(err).ToNot(HaveOccurred())
log.Logf("resourceVersion=%s", es.Status.SyncedResourceVersion)
for _, cond := range es.Status.Conditions {
log.Logf("condition: status=%s type=%s reason=%s message=%s", cond.Status, cond.Type, cond.Reason, cond.Message)
}
// list events for given
evs, err := f.KubeClientSet.CoreV1().Events(esNamespace).List(context.Background(), metav1.ListOptions{
FieldSelector: "involvedObject.name=" + esName + ",involvedObject.kind=ExternalSecret",
})
Expect(err).ToNot(HaveOccurred())
for _, ev := range evs.Items {
log.Logf("ev reason=%s message=%s", ev.Reason, ev.Message)
}
// print most recent logs of default eso installation
podList, err := f.KubeClientSet.CoreV1().Pods("default").List(
context.Background(),
metav1.ListOptions{LabelSelector: "app.kubernetes.io/instance=eso,app.kubernetes.io/name=external-secrets"})
Expect(err).ToNot(HaveOccurred())
numLines := int64(60)
for i := range podList.Items {
pod := podList.Items[i]
for _, con := range pod.Spec.Containers {
for _, b := range []bool{true, false} {
resp := f.KubeClientSet.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, &v1.PodLogOptions{
Container: con.Name,
Previous: b,
TailLines: &numLines,
}).Do(context.TODO())
err := resp.Error()
if err != nil {
continue
}
logs, err := resp.Raw()
if err != nil {
continue
}
log.Logf("[%s]: %s", "eso", string(logs))
}
}
}
}
func equalSecrets(exp, ts *v1.Secret) bool {
if exp.Type != ts.Type {
return false

View file

@ -19,5 +19,5 @@ import (
// Logf logs the format string to ginkgo stdout.
func Logf(format string, args ...interface{}) {
ginkgo.GinkgoWriter.Printf(format, args...)
ginkgo.GinkgoWriter.Printf(format+"\n", args...)
}

View file

@ -96,6 +96,7 @@ func TableFunc(f *Framework, prov SecretStoreProvider) func(...func(*TestCase))
// wait for Kind=Secret to have the expected data
secret, err := tc.Framework.WaitForSecretValue(tc.Framework.Namespace.Name, TargetSecretName, tc.ExpectedSecret)
if err != nil {
f.printESDebugLogs(tc.ExternalSecret.Name, tc.ExternalSecret.Namespace)
log.Logf("Did not match. Expected: %+v, Got: %+v", tc.ExpectedSecret, secret)
}

2
go.mod
View file

@ -98,6 +98,7 @@ require (
github.com/hashicorp/golang-lru v0.5.4
github.com/maxbrunsfeld/counterfeiter/v6 v6.5.0
github.com/sethvargo/go-password v0.2.0
github.com/spf13/pflag v1.0.5
sigs.k8s.io/yaml v1.3.0
)
@ -206,7 +207,6 @@ require (
github.com/shopspring/decimal v1.3.1 // indirect
github.com/sony/gobreaker v0.5.0 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect

99
pkg/cache/cache.go vendored Normal file
View file

@ -0,0 +1,99 @@
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cache
import (
"fmt"
lru "github.com/hashicorp/golang-lru"
)
// Cache is a generic lru cache that allows you to
// lookup values using a key and a version.
// By design, this cache allows access to only a single version of a given key.
// A version mismatch is considered a cache miss and the key gets evicted if it exists.
// When a key is evicted a optional cleanup function is called.
type Cache[T any] struct {
lru *lru.Cache
size int
cleanupFunc cleanupFunc[T]
}
// Key is the cache lookup key.
type Key struct {
Name string
Namespace string
Kind string
}
type value[T any] struct {
Version string
Client T
}
type cleanupFunc[T any] func(client T)
// New constructs a new lru cache with the desired size and cleanup func.
func New[T any](size int, cleanup cleanupFunc[T]) (*Cache[T], error) {
lruCache, err := lru.NewWithEvict(size, func(_, val any) {
if cleanup == nil {
return
}
cleanup(val.(value[T]).Client)
})
if err != nil {
return nil, fmt.Errorf("unable to create lru: %w", err)
}
return &Cache[T]{
lru: lruCache,
size: size,
cleanupFunc: cleanup,
}, nil
}
// Must creates a new lru cache with the desired size and cleanup func
// This function panics if a error occurrs.
func Must[T any](size int, cleanup cleanupFunc[T]) *Cache[T] {
c, err := New(size, cleanup)
if err != nil {
panic(err)
}
return c
}
// Get retrieves the desired value using the key and
// compares the version. If there is a mismatch
// it is considered a cache miss and the existing key is purged.
func (c *Cache[T]) Get(version string, key Key) (T, bool) {
val, ok := c.lru.Get(key)
if ok {
cachedClient := val.(value[T])
if cachedClient.Version == version {
return cachedClient.Client, true
}
c.lru.Remove(key)
}
return value[T]{}.Client, false
}
// Add adds a new value for the given key/version.
func (c *Cache[T]) Add(version string, key Key, client T) {
c.lru.Add(key, value[T]{Version: version, Client: client})
}
// Contains returns true if a value with the given key exists.
func (c *Cache[T]) Contains(key Key) bool {
return c.lru.Contains(key)
}

99
pkg/cache/cache_test.go vendored Normal file
View file

@ -0,0 +1,99 @@
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cache
import (
"testing"
"github.com/stretchr/testify/assert"
)
type client struct{}
var cacheKey = Key{Name: "foo"}
func TestCacheAdd(t *testing.T) {
c, err := New[client](1, nil)
if err != nil {
t.Fail()
}
cl := client{}
c.Add("", cacheKey, cl)
cachedVal, _ := c.Get("", cacheKey)
assert.EqualValues(t, cl, cachedVal)
}
func TestCacheContains(t *testing.T) {
c, err := New[client](1, nil)
if err != nil {
t.Fail()
}
cl := client{}
c.Add("", cacheKey, cl)
exists := c.Contains(cacheKey)
notExists := c.Contains(Key{Name: "does not exist"})
assert.True(t, exists)
assert.False(t, notExists)
assert.Nil(t, err)
}
func TestCacheGet(t *testing.T) {
c, err := New[*client](1, nil)
if err != nil {
t.Fail()
}
cachedVal, ok := c.Get("", cacheKey)
assert.Nil(t, cachedVal)
assert.False(t, ok)
}
func TestCacheGetInvalidVersion(t *testing.T) {
var cleanupCalled bool
c, err := New(1, func(client *client) {
cleanupCalled = true
})
if err != nil {
t.Fail()
}
cl := &client{}
c.Add("", cacheKey, cl)
cachedVal, ok := c.Get("invalid", cacheKey)
assert.Nil(t, cachedVal)
assert.False(t, ok)
assert.True(t, cleanupCalled)
}
func TestCacheEvict(t *testing.T) {
var cleanupCalled bool
c, err := New(1, func(client client) {
cleanupCalled = true
})
if err != nil {
t.Fail()
}
// add first version
c.Add("", Key{Name: "foo"}, client{})
assert.False(t, cleanupCalled)
// adding a second version should evict old one
c.Add("", Key{Name: "bar"}, client{})
assert.True(t, cleanupCalled)
}

38
pkg/feature/feature.go Normal file
View file

@ -0,0 +1,38 @@
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package feature
import (
"github.com/spf13/pflag"
)
// Feature contains the CLI flags that a provider exposes to a user.
// A optional Initialize func is called once the flags have been parsed.
// A provider can use this to do late-initialization using the defined cli args.
type Feature struct {
Flags *pflag.FlagSet
Initialize func()
}
var features = make([]Feature, 0)
// Features returns all registered features.
func Features() []Feature {
return features
}
// Register registers a new feature.
func Register(f Feature) {
features = append(features, f)
}

View file

@ -26,6 +26,7 @@ import (
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sts"
"github.com/aws/aws-sdk-go/service/sts/stsiface"
"github.com/spf13/pflag"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
@ -34,6 +35,8 @@ import (
ctrlcfg "sigs.k8s.io/controller-runtime/pkg/client/config"
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
"github.com/external-secrets/external-secrets/pkg/cache"
"github.com/external-secrets/external-secrets/pkg/feature"
"github.com/external-secrets/external-secrets/pkg/provider/aws/util"
)
@ -44,17 +47,10 @@ type Config struct {
APIRetries int
}
type SessionCache struct {
Name string
Namespace string
Kind string
ResourceVersion string
}
var (
log = ctrl.Log.WithName("provider").WithName("aws")
sessions = make(map[SessionCache]*session.Session)
EnableCache bool
enableSessionCache bool
sessionCache *cache.Cache[*session.Session]
)
const (
@ -71,6 +67,15 @@ const (
errMissingAKID = "missing AccessKeyID"
)
func init() {
fs := pflag.NewFlagSet("aws-auth", pflag.ExitOnError)
fs.BoolVar(&enableSessionCache, "experimental-enable-aws-session-cache", false, "Enable experimental AWS session cache. External secret will reuse the AWS session without creating a new one on each request.")
feature.Register(feature.Feature{
Flags: fs,
})
sessionCache = cache.Must[*session.Session](1024, nil)
}
// New creates a new aws session based on the provided store
// it uses the following authentication mechanisms in order:
// * service-account token authentication via AssumeRoleWithWebIdentity
@ -111,7 +116,7 @@ func New(ctx context.Context, store esv1beta1.GenericStore, kube client.Client,
config.WithRegion(prov.Region)
}
sess, err := getAWSSession(config, EnableCache, store.GetName(), store.GetTypeMeta().Kind, namespace, store.GetObjectMeta().ResourceVersion)
sess, err := getAWSSession(config, enableSessionCache, store.GetName(), store.GetTypeMeta().Kind, namespace, store.GetObjectMeta().ResourceVersion)
if err != nil {
return nil, err
}
@ -327,17 +332,16 @@ func DefaultSTSProvider(sess *session.Session) stsiface.STSAPI {
// getAWSSession checks if an AWS session should be reused
// it returns the aws session or an error.
func getAWSSession(config *aws.Config, enableCache bool, name, kind, namespace, resourceVersion string) (*session.Session, error) {
tmpSession := SessionCache{
key := cache.Key{
Name: name,
Namespace: namespace,
Kind: kind,
ResourceVersion: resourceVersion,
}
if enableCache {
sess, ok := sessions[tmpSession]
sess, ok := sessionCache.Get(resourceVersion, key)
if ok {
log.Info("reusing aws session", "SecretStore", tmpSession.Name, "namespace", tmpSession.Namespace, "kind", tmpSession.Kind, "resourceversion", tmpSession.ResourceVersion)
log.Info("reusing aws session", "SecretStore", key.Name, "namespace", key.Namespace, "kind", key.Kind, "resourceversion", resourceVersion)
return sess, nil
}
}
@ -354,7 +358,7 @@ func getAWSSession(config *aws.Config, enableCache bool, name, kind, namespace,
}
if enableCache {
sessions[tmpSession] = sess
sessionCache.Add(resourceVersion, key, sess)
}
return sess, nil
}

View file

@ -1,106 +0,0 @@
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package vault
import (
"context"
"errors"
"fmt"
"sync"
lru "github.com/hashicorp/golang-lru"
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
)
type clientCache struct {
cache *lru.Cache
Size int
initialized bool
mu sync.Mutex
}
type clientCacheKey struct {
Name string
Namespace string
Kind string
}
type clientCacheValue struct {
ResourceVersion string
Client Client
}
func (c *clientCache) initialize() error {
if !c.initialized {
var err error
c.cache, err = lru.New(c.Size)
if err != nil {
return fmt.Errorf(errVaultCacheCreate, err)
}
c.initialized = true
}
return nil
}
func (c *clientCache) get(ctx context.Context, store esv1beta1.GenericStore, key clientCacheKey) (Client, bool, error) {
value, ok := c.cache.Get(key)
if ok {
cachedClient := value.(clientCacheValue)
if cachedClient.ResourceVersion == store.GetObjectMeta().ResourceVersion {
return cachedClient.Client, true, nil
}
// revoke token and clear old item from cache if resource has been updated
err := revokeTokenIfValid(ctx, cachedClient.Client)
if err != nil {
return nil, false, err
}
c.cache.Remove(key)
}
return nil, false, nil
}
func (c *clientCache) add(ctx context.Context, store esv1beta1.GenericStore, key clientCacheKey, client Client) error {
// don't let the LRU cache evict items
// remove the oldest item manually when needed so we can do some cleanup
for c.cache.Len() >= c.Size {
_, value, ok := c.cache.RemoveOldest()
if !ok {
return errors.New(errVaultCacheRemove)
}
cachedClient := value.(clientCacheValue)
err := revokeTokenIfValid(ctx, cachedClient.Client)
if err != nil {
return fmt.Errorf(errVaultRevokeToken, err)
}
}
evicted := c.cache.Add(key, clientCacheValue{ResourceVersion: store.GetObjectMeta().ResourceVersion, Client: client})
if evicted {
return errors.New(errVaultCacheEviction)
}
return nil
}
func (c *clientCache) contains(key clientCacheKey) bool {
return c.cache.Contains(key)
}
func (c *clientCache) lock() {
c.mu.Lock()
}
func (c *clientCache) unlock() {
c.mu.Unlock()
}

View file

@ -32,6 +32,7 @@ import (
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/spf13/pflag"
"github.com/tidwall/gjson"
authenticationv1 "k8s.io/api/authentication/v1"
corev1 "k8s.io/api/core/v1"
@ -45,6 +46,8 @@ import (
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
"github.com/external-secrets/external-secrets/pkg/cache"
"github.com/external-secrets/external-secrets/pkg/feature"
"github.com/external-secrets/external-secrets/pkg/find"
"github.com/external-secrets/external-secrets/pkg/utils"
)
@ -52,8 +55,9 @@ import (
var (
_ esv1beta1.Provider = &connector{}
_ esv1beta1.SecretsClient = &client{}
EnableCache bool
VaultClientCache clientCache
enableCache bool
logger = ctrl.Log.WithName("provider").WithName("vault")
clientCache *cache.Cache[Client]
)
const (
@ -198,14 +202,6 @@ type client struct {
storeKind string
}
func init() {
esv1beta1.Register(&connector{
newVaultClient: newVaultClient,
}, &esv1beta1.SecretStoreProvider{
Vault: &esv1beta1.VaultProvider{},
})
}
func newVaultClient(c *vault.Config) (Client, error) {
cl, err := vault.NewClient(c)
if err != nil {
@ -227,30 +223,17 @@ func newVaultClient(c *vault.Config) (Client, error) {
return out, nil
}
func getVaultClient(ctx context.Context, c *connector, store esv1beta1.GenericStore, cfg *vault.Config) (Client, error) {
func getVaultClient(c *connector, store esv1beta1.GenericStore, cfg *vault.Config) (Client, error) {
isStaticToken := store.GetSpec().Provider.Vault.Auth.TokenSecretRef != nil
useCache := EnableCache && !isStaticToken
useCache := enableCache && !isStaticToken
if useCache {
VaultClientCache.lock()
defer VaultClientCache.unlock()
err := VaultClientCache.initialize()
if err != nil {
return nil, err
}
}
key := clientCacheKey{
key := cache.Key{
Name: store.GetObjectMeta().Name,
Namespace: store.GetObjectMeta().Namespace,
Kind: store.GetTypeMeta().Kind,
}
if useCache {
client, ok, err := VaultClientCache.get(ctx, store, key)
if err != nil {
return nil, err
}
client, ok := clientCache.Get(store.GetObjectMeta().ResourceVersion, key)
if ok {
return client, nil
}
@ -261,11 +244,8 @@ func getVaultClient(ctx context.Context, c *connector, store esv1beta1.GenericSt
return nil, fmt.Errorf(errVaultClient, err)
}
if useCache && !VaultClientCache.contains(key) {
err = VaultClientCache.add(ctx, store, key, client)
if err != nil {
return nil, err
}
if useCache && !clientCache.Contains(key) {
clientCache.Add(store.GetObjectMeta().ResourceVersion, key, client)
}
return client, nil
}
@ -306,7 +286,7 @@ func (c *connector) newClient(ctx context.Context, store esv1beta1.GenericStore,
kube: kube,
corev1: corev1,
store: vaultSpec,
log: ctrl.Log.WithName("provider").WithName("vault"),
log: logger,
namespace: namespace,
storeKind: store.GetObjectKind().GroupVersionKind().Kind,
}
@ -316,7 +296,7 @@ func (c *connector) newClient(ctx context.Context, store esv1beta1.GenericStore,
return nil, err
}
client, err := getVaultClient(ctx, c, store, cfg)
client, err := getVaultClient(c, store, cfg)
if err != nil {
return nil, fmt.Errorf(errVaultClient, err)
}
@ -723,7 +703,7 @@ 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, it wasn't sourced from a TokenSecretRef,
// and token caching isn't enabled
if !EnableCache && v.client.Token() != "" && v.store.Auth.TokenSecretRef == nil {
if !enableCache && v.client.Token() != "" && v.store.Auth.TokenSecretRef == nil {
err := revokeTokenIfValid(ctx, v.client)
if err != nil {
return err
@ -1415,3 +1395,29 @@ func (v *client) requestTokenWithCertAuth(ctx context.Context, certAuth *esv1bet
v.client.SetToken(token)
return nil
}
func init() {
var vaultTokenCacheSize int
fs := pflag.NewFlagSet("vault", pflag.ExitOnError)
fs.BoolVar(&enableCache, "experimental-enable-vault-token-cache", false, "Enable experimental Vault token cache. External secrets will reuse the Vault token without creating a new one on each request.")
fs.IntVar(&vaultTokenCacheSize, "experimental-vault-token-cache-size", 100, "Maximum size of Vault token cache. Only used if --experimental-enable-vault-token-cache is set.")
lateInit := func() {
logger.Info("initializing vault cache with size=%d", vaultTokenCacheSize)
clientCache = cache.Must(vaultTokenCacheSize, func(client Client) {
err := revokeTokenIfValid(context.Background(), client)
if err != nil {
logger.Error(err, "unable to revoke cached token on eviction")
}
})
}
feature.Register(feature.Feature{
Flags: fs,
Initialize: lateInit,
})
esv1beta1.Register(&connector{
newVaultClient: newVaultClient,
}, &esv1beta1.SecretStoreProvider{
Vault: &esv1beta1.VaultProvider{},
})
}