|
|
@@ -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
|
|
|
}
|