Przeglądaj źródła

Added SetSecret signature and NotImplemented methods for every provider

Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com>
Signed-off-by: Marcin Kubica <marcin.kubica@engineerbetter.com>
Signed-off-by: William Young <will.young@engineerbetter.com>
Signed-off-by: Dominic Meddick <dom.meddick@engineerbetter.com>
Gustavo Carvalho 4 lat temu
rodzic
commit
a0def472bb

+ 3 - 0
apis/externalsecrets/v1beta1/provider.go

@@ -58,6 +58,9 @@ type SecretsClient interface {
 	// then the secret entry will be deleted depending on the deletionPolicy.
 	GetSecret(ctx context.Context, ref ExternalSecretDataRemoteRef) ([]byte, error)
 
+	// SetSecret willl write a single secret into the provider
+	SetSecret() error
+
 	// Validate checks if the client is configured correctly
 	// and is able to retrieve secrets from the provider.
 	// If the validation result is unknown it will be ignored.

+ 5 - 0
apis/externalsecrets/v1beta1/provider_schema_test.go

@@ -30,6 +30,11 @@ func (p *PP) NewClient(ctx context.Context, store GenericStore, kube client.Clie
 	return p, nil
 }
 
+// SetSecret writes a single secret into a provider.
+func (p *PP) SetSecret() error {
+	return nil
+}
+
 // GetSecret returns a single secret from the provider.
 func (p *PP) GetSecret(ctx context.Context, ref ExternalSecretDataRemoteRef) ([]byte, error) {
 	return []byte("NOOP"), nil

+ 4 - 0
pkg/provider/akeyless/akeyless.go

@@ -165,6 +165,10 @@ func (a *Akeyless) Validate() (esv1beta1.ValidationResult, error) {
 	return esv1beta1.ValidationResultReady, nil
 }
 
+func (a *Akeyless) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // Implements store.Client.GetSecret Interface.
 // Retrieves a secret with the secret name defined in ref.Name.
 func (a *Akeyless) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {

+ 4 - 0
pkg/provider/alibaba/kms.go

@@ -114,6 +114,10 @@ func (c *Client) setAuth(ctx context.Context) error {
 	return nil
 }
 
+func (kms *KeyManagementService) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // Empty GetAllSecrets.
 func (kms *KeyManagementService) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented

+ 6 - 1
pkg/provider/aws/parameterstore/parameterstore.go

@@ -60,7 +60,12 @@ func New(sess *session.Session) (*ParameterStore, error) {
 	}, nil
 }
 
-// Empty GetAllSecrets.
+// Not Implemented SetSecret.
+func (pm *ParameterStore) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
+// GetAllSecrets fetches information from multiple secrets into a single kubernetes secret.
 func (pm *ParameterStore) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	if ref.Name != nil {
 		return pm.findByName(ref)

+ 5 - 0
pkg/provider/aws/secretsmanager/secretsmanager.go

@@ -104,6 +104,11 @@ func (sm *SecretsManager) fetch(_ context.Context, ref esv1beta1.ExternalSecretD
 	return secretOut, nil
 }
 
+// Not Implemented SetSecret.
+func (sm *SecretsManager) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // 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 {

+ 5 - 0
pkg/provider/azure/keyvault/keyvault.go

@@ -195,6 +195,11 @@ func (a *Azure) ValidateStore(store esv1beta1.GenericStore) error {
 	return nil
 }
 
+// Not Implemented SetSecret.
+func (a *Azure) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // Implements store.Client.GetAllSecrets Interface.
 // Retrieves a map[string][]byte with the secret names as key and the secret itself as the calue.
 func (a *Azure) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {

+ 5 - 0
pkg/provider/fake/fake.go

@@ -55,6 +55,11 @@ func getProvider(store esv1beta1.GenericStore) (*esv1beta1.FakeProvider, error)
 	return spc.Provider.Fake, nil
 }
 
+// Not Implemented SetSecret.
+func (p *Provider) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // Empty GetAllSecrets.
 func (p *Provider) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented

+ 5 - 0
pkg/provider/gcp/secretmanager/secretsmanager.go

@@ -214,6 +214,11 @@ func (sm *ProviderGCP) NewClient(ctx context.Context, store esv1beta1.GenericSto
 	return sm, nil
 }
 
+// Not Implemented SetSecret.
+func (sm *ProviderGCP) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // 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) {
 	if ref.Name != nil {

+ 5 - 0
pkg/provider/gitlab/gitlab.go

@@ -156,6 +156,11 @@ func (g *Gitlab) NewClient(ctx context.Context, store esv1beta1.GenericStore, ku
 	return g, nil
 }
 
+// Not Implemented SetSecret.
+func (g *Gitlab) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // Empty GetAllSecrets.
 func (g *Gitlab) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented

+ 5 - 0
pkg/provider/ibm/provider.go

@@ -100,6 +100,11 @@ func (c *client) setAuth(ctx context.Context) error {
 	return nil
 }
 
+// Not Implemented SetSecret.
+func (ibm *providerIBM) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // Empty GetAllSecrets.
 func (ibm *providerIBM) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented

+ 5 - 0
pkg/provider/kubernetes/kubernetes.go

@@ -125,6 +125,11 @@ func (k *ProviderKubernetes) Close(ctx context.Context) error {
 	return nil
 }
 
+// Not Implemented SetSecret.
+func (k *ProviderKubernetes) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 func (k *ProviderKubernetes) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
 	if ref.Property == "" {
 		return nil, fmt.Errorf(errPropertyNotFound)

+ 5 - 0
pkg/provider/oracle/oracle.go

@@ -65,6 +65,11 @@ type VMInterface interface {
 	GetSecretBundleByName(ctx context.Context, request secrets.GetSecretBundleByNameRequest) (secrets.GetSecretBundleByNameResponse, error)
 }
 
+// Not Implemented SetSecret.
+func (vms *VaultManagementService) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // Empty GetAllSecrets.
 func (vms *VaultManagementService) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented

+ 5 - 0
pkg/provider/senhasegura/dsm/dsm.go

@@ -90,6 +90,11 @@ func New(isoSession *senhaseguraAuth.SenhaseguraIsoSession) (*DSM, error) {
 	}, nil
 }
 
+// Not Implemented SetSecret.
+func (dsm *DSM) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 /*
 	GetSecret implements ESO interface and get a single secret from senhasegura provider with DSM service
 */

+ 6 - 0
pkg/provider/testing/fake/fake.go

@@ -30,6 +30,7 @@ type Client struct {
 	GetSecretFn     func(context.Context, esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error)
 	GetSecretMapFn  func(context.Context, esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error)
 	GetAllSecretsFn func(context.Context, esv1beta1.ExternalSecretFind) (map[string][]byte, error)
+	SetSecretFn     func() error
 }
 
 // New returns a fake provider/client.
@@ -63,6 +64,11 @@ func (v *Client) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecret
 	return v.GetAllSecretsFn(ctx, ref)
 }
 
+// Not Implemented SetSecret.
+func (v *Client) SetSecret() error {
+	return v.SetSecretFn()
+}
+
 // GetSecret implements the provider.Provider interface.
 func (v *Client) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
 	return v.GetSecretFn(ctx, ref)

+ 7 - 3
pkg/provider/vault/vault.go

@@ -350,9 +350,13 @@ func (c *connector) ValidateStore(store esv1beta1.GenericStore) error {
 	return nil
 }
 
-// Empty GetAllSecrets.
-// GetAllSecrets
-// First load all secrets from secretStore path configuration.
+// Not Implemented SetSecret.
+func (v *client) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
+// GetAllSecrets gets multiple secrets from the provider and loads into a kubernetes secret.
+// First load all secrets from secretStore path configuration
 // Then, gets secrets from a matching name or matching custom_metadata.
 func (v *client) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	if v.store.Version == esv1beta1.VaultKVStoreV1 {

+ 5 - 0
pkg/provider/webhook/webhook.go

@@ -111,6 +111,11 @@ func (w *WebHook) getStoreSecret(ctx context.Context, ref esmeta.SecretKeySelect
 	return secret, nil
 }
 
+// Not Implemented SetSecret.
+func (w *WebHook) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // Empty GetAllSecrets.
 func (w *WebHook) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented

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

@@ -53,8 +53,122 @@ func adaptInput(store esv1beta1.GenericStore) (*common.SecretsClientInput, error
 	}, nil
 }
 
-func newSecretGetter(ctx context.Context, apiEndpoint string, authorizedKey *iamkey.Key, caCertificate []byte) (common.SecretGetter, error) {
-	lockboxClient, err := client.NewGrpcLockboxClient(ctx, apiEndpoint, authorizedKey, caCertificate)
+func (p *lockboxProvider) getOrCreateLockboxClient(ctx context.Context, apiEndpoint string, authorizedKey *iamkey.Key, caCertificate []byte) (client.LockboxClient, error) {
+	p.lockboxClientMapMutex.Lock()
+	defer p.lockboxClientMapMutex.Unlock()
+
+	if _, ok := p.lockboxClientMap[apiEndpoint]; !ok {
+		log.Info("creating LockboxClient", "apiEndpoint", apiEndpoint)
+
+		lockboxClient, err := p.yandexCloudCreator.CreateLockboxClient(ctx, apiEndpoint, authorizedKey, caCertificate)
+		if err != nil {
+			return nil, err
+		}
+		p.lockboxClientMap[apiEndpoint] = lockboxClient
+	}
+	return p.lockboxClientMap[apiEndpoint], nil
+}
+
+func (p *lockboxProvider) getOrCreateIamToken(ctx context.Context, apiEndpoint string, authorizedKey *iamkey.Key) (*client.IamToken, error) {
+	p.iamTokenMapMutex.Lock()
+	defer p.iamTokenMapMutex.Unlock()
+
+	iamTokenKey := buildIamTokenKey(authorizedKey)
+	if iamToken, ok := p.iamTokenMap[iamTokenKey]; !ok || !p.isIamTokenUsable(iamToken) {
+		log.Info("creating IAM token", "authorizedKeyId", authorizedKey.Id)
+
+		iamToken, err := p.yandexCloudCreator.CreateIamToken(ctx, apiEndpoint, authorizedKey)
+		if err != nil {
+			return nil, err
+		}
+
+		log.Info("created IAM token", "authorizedKeyId", authorizedKey.Id, "expiresAt", iamToken.ExpiresAt)
+
+		p.iamTokenMap[iamTokenKey] = iamToken
+	}
+	return p.iamTokenMap[iamTokenKey], nil
+}
+
+func (p *lockboxProvider) isIamTokenUsable(iamToken *client.IamToken) bool {
+	now := p.yandexCloudCreator.Now()
+	return now.Add(maxSecretsClientLifetime).Before(iamToken.ExpiresAt)
+}
+
+func buildIamTokenKey(authorizedKey *iamkey.Key) iamTokenKey {
+	privateKeyHash := sha256.Sum256([]byte(authorizedKey.PrivateKey))
+	return iamTokenKey{
+		authorizedKey.GetId(),
+		authorizedKey.GetServiceAccountId(),
+		hex.EncodeToString(privateKeyHash[:]),
+	}
+}
+
+// Used for testing.
+func (p *lockboxProvider) isIamTokenCached(authorizedKey *iamkey.Key) bool {
+	p.iamTokenMapMutex.Lock()
+	defer p.iamTokenMapMutex.Unlock()
+
+	_, ok := p.iamTokenMap[buildIamTokenKey(authorizedKey)]
+	return ok
+}
+
+func (p *lockboxProvider) cleanUpIamTokenMap() {
+	p.iamTokenMapMutex.Lock()
+	defer p.iamTokenMapMutex.Unlock()
+
+	for key, value := range p.iamTokenMap {
+		if p.yandexCloudCreator.Now().After(value.ExpiresAt) {
+			log.Info("deleting IAM token", "authorizedKeyId", key.authorizedKeyID)
+			delete(p.iamTokenMap, key)
+		}
+	}
+}
+
+func (p *lockboxProvider) ValidateStore(store esv1beta1.GenericStore) error {
+	return nil
+}
+
+// lockboxSecretsClient is a secrets client for Yandex Lockbox.
+type lockboxSecretsClient struct {
+	lockboxClient client.LockboxClient
+	iamToken      string
+}
+
+// Not Implemented SetSecret.
+func (c *lockboxSecretsClient) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
+// Empty GetAllSecrets.
+func (c *lockboxSecretsClient) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
+	// TO be implemented
+	return nil, fmt.Errorf("GetAllSecrets not implemented")
+}
+
+// GetSecret returns a single secret from the provider.
+func (c *lockboxSecretsClient) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
+	entries, err := c.lockboxClient.GetPayloadEntries(ctx, c.iamToken, ref.Key, ref.Version)
+	if err != nil {
+		return nil, fmt.Errorf("unable to request secret payload to get secret: %w", err)
+	}
+
+	if ref.Property == "" {
+		keyToValue := make(map[string]interface{}, len(entries))
+		for _, entry := range entries {
+			value, err := getValueAsIs(entry)
+			if err != nil {
+				return nil, err
+			}
+			keyToValue[entry.Key] = value
+		}
+		out, err := json.Marshal(keyToValue)
+		if err != nil {
+			return nil, fmt.Errorf("failed to marshal secret: %w", err)
+		}
+		return out, nil
+	}
+
+	entry, err := findEntryByKey(entries, ref.Property)
 	if err != nil {
 		return nil, err
 	}