provider.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. /*
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. package ibm
  13. import (
  14. "context"
  15. "encoding/json"
  16. "fmt"
  17. "strconv"
  18. "strings"
  19. "time"
  20. core "github.com/IBM/go-sdk-core/v5/core"
  21. sm "github.com/IBM/secrets-manager-go-sdk/secretsmanagerv1"
  22. gjson "github.com/tidwall/gjson"
  23. corev1 "k8s.io/api/core/v1"
  24. types "k8s.io/apimachinery/pkg/types"
  25. ctrl "sigs.k8s.io/controller-runtime"
  26. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  27. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  28. utils "github.com/external-secrets/external-secrets/pkg/utils"
  29. )
  30. const (
  31. SecretsManagerEndpointEnv = "IBM_SECRETSMANAGER_ENDPOINT"
  32. STSEndpointEnv = "IBM_STS_ENDPOINT"
  33. SSMEndpointEnv = "IBM_SSM_ENDPOINT"
  34. errIBMClient = "cannot setup new ibm client: %w"
  35. errIBMCredSecretName = "invalid IBM SecretStore resource: missing IBM APIKey"
  36. errUninitalizedIBMProvider = "provider IBM is not initialized"
  37. errInvalidClusterStoreMissingSKNamespace = "invalid ClusterStore, missing namespace"
  38. errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
  39. errMissingSAK = "missing SecretAccessKey"
  40. errJSONSecretUnmarshal = "unable to unmarshal secret: %w"
  41. )
  42. // https://github.com/external-secrets/external-secrets/issues/644
  43. var _ esv1beta1.SecretsClient = &providerIBM{}
  44. var _ esv1beta1.Provider = &providerIBM{}
  45. type SecretManagerClient interface {
  46. GetSecret(getSecretOptions *sm.GetSecretOptions) (result *sm.GetSecret, response *core.DetailedResponse, err error)
  47. }
  48. type providerIBM struct {
  49. IBMClient SecretManagerClient
  50. }
  51. type client struct {
  52. kube kclient.Client
  53. store *esv1beta1.IBMProvider
  54. namespace string
  55. storeKind string
  56. credentials []byte
  57. }
  58. var log = ctrl.Log.WithName("provider").WithName("ibm").WithName("secretsmanager")
  59. func (c *client) setAuth(ctx context.Context) error {
  60. credentialsSecret := &corev1.Secret{}
  61. credentialsSecretName := c.store.Auth.SecretRef.SecretAPIKey.Name
  62. if credentialsSecretName == "" {
  63. return fmt.Errorf(errIBMCredSecretName)
  64. }
  65. objectKey := types.NamespacedName{
  66. Name: credentialsSecretName,
  67. Namespace: c.namespace,
  68. }
  69. // only ClusterStore is allowed to set namespace (and then it's required)
  70. if c.storeKind == esv1beta1.ClusterSecretStoreKind {
  71. if c.store.Auth.SecretRef.SecretAPIKey.Namespace == nil {
  72. return fmt.Errorf(errInvalidClusterStoreMissingSKNamespace)
  73. }
  74. objectKey.Namespace = *c.store.Auth.SecretRef.SecretAPIKey.Namespace
  75. }
  76. err := c.kube.Get(ctx, objectKey, credentialsSecret)
  77. if err != nil {
  78. return fmt.Errorf(errFetchSAKSecret, err)
  79. }
  80. c.credentials = credentialsSecret.Data[c.store.Auth.SecretRef.SecretAPIKey.Key]
  81. if (c.credentials == nil) || (len(c.credentials) == 0) {
  82. return fmt.Errorf(errMissingSAK)
  83. }
  84. return nil
  85. }
  86. // Not Implemented SetSecret.
  87. func (ibm *providerIBM) SetSecret(ctx context.Context, value []byte, remoteRef esv1beta1.PushRemoteRef) error {
  88. return fmt.Errorf("not implemented")
  89. }
  90. // Empty GetAllSecrets.
  91. func (ibm *providerIBM) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  92. // TO be implemented
  93. return nil, fmt.Errorf("GetAllSecrets not implemented")
  94. }
  95. func (ibm *providerIBM) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  96. if utils.IsNil(ibm.IBMClient) {
  97. return nil, fmt.Errorf(errUninitalizedIBMProvider)
  98. }
  99. secretType := sm.GetSecretOptionsSecretTypeArbitraryConst
  100. secretName := ref.Key
  101. nameSplitted := strings.Split(secretName, "/")
  102. if len(nameSplitted) > 1 {
  103. secretType = nameSplitted[0]
  104. secretName = nameSplitted[1]
  105. }
  106. switch secretType {
  107. case sm.GetSecretOptionsSecretTypeArbitraryConst:
  108. return getArbitrarySecret(ibm, &secretName)
  109. case sm.CreateSecretOptionsSecretTypeUsernamePasswordConst:
  110. if ref.Property == "" {
  111. return nil, fmt.Errorf("remoteRef.property required for secret type username_password")
  112. }
  113. return getUsernamePasswordSecret(ibm, &secretName, ref)
  114. case sm.CreateSecretOptionsSecretTypeIamCredentialsConst:
  115. return getIamCredentialsSecret(ibm, &secretName)
  116. case sm.CreateSecretOptionsSecretTypeImportedCertConst:
  117. if ref.Property == "" {
  118. return nil, fmt.Errorf("remoteRef.property required for secret type imported_cert")
  119. }
  120. return getImportCertSecret(ibm, &secretName, ref)
  121. case sm.CreateSecretOptionsSecretTypePublicCertConst:
  122. if ref.Property == "" {
  123. return nil, fmt.Errorf("remoteRef.property required for secret type public_cert")
  124. }
  125. return getPublicCertSecret(ibm, &secretName, ref)
  126. case sm.CreateSecretOptionsSecretTypePrivateCertConst:
  127. if ref.Property == "" {
  128. return nil, fmt.Errorf("remoteRef.property required for secret type private_cert")
  129. }
  130. return getPrivateCertSecret(ibm, &secretName, ref)
  131. case sm.CreateSecretOptionsSecretTypeKvConst:
  132. return getKVSecret(ibm, &secretName, ref)
  133. default:
  134. return nil, fmt.Errorf("unknown secret type %s", secretType)
  135. }
  136. }
  137. func getArbitrarySecret(ibm *providerIBM, secretName *string) ([]byte, error) {
  138. response, _, err := ibm.IBMClient.GetSecret(
  139. &sm.GetSecretOptions{
  140. SecretType: core.StringPtr(sm.GetSecretOptionsSecretTypeArbitraryConst),
  141. ID: secretName,
  142. })
  143. if err != nil {
  144. return nil, err
  145. }
  146. secret := response.Resources[0].(*sm.SecretResource)
  147. secretData := secret.SecretData.(map[string]interface{})
  148. arbitrarySecretPayload := secretData["payload"].(string)
  149. return []byte(arbitrarySecretPayload), nil
  150. }
  151. func getImportCertSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  152. response, _, err := ibm.IBMClient.GetSecret(
  153. &sm.GetSecretOptions{
  154. SecretType: core.StringPtr(sm.CreateSecretOptionsSecretTypeImportedCertConst),
  155. ID: secretName,
  156. })
  157. if err != nil {
  158. return nil, err
  159. }
  160. secret := response.Resources[0].(*sm.SecretResource)
  161. secretData := secret.SecretData.(map[string]interface{})
  162. if val, ok := secretData[ref.Property]; ok {
  163. return []byte(val.(string)), nil
  164. }
  165. return nil, fmt.Errorf("key %s does not exist in secret %s", ref.Property, ref.Key)
  166. }
  167. func getPublicCertSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  168. response, _, err := ibm.IBMClient.GetSecret(
  169. &sm.GetSecretOptions{
  170. SecretType: core.StringPtr(sm.CreateSecretOptionsSecretTypePublicCertConst),
  171. ID: secretName,
  172. })
  173. if err != nil {
  174. return nil, err
  175. }
  176. secret := response.Resources[0].(*sm.SecretResource)
  177. secretData := secret.SecretData.(map[string]interface{})
  178. if val, ok := secretData[ref.Property]; ok {
  179. return []byte(val.(string)), nil
  180. }
  181. return nil, fmt.Errorf("key %s does not exist in secret %s", ref.Property, ref.Key)
  182. }
  183. func getPrivateCertSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  184. response, _, err := ibm.IBMClient.GetSecret(
  185. &sm.GetSecretOptions{
  186. SecretType: core.StringPtr(sm.CreateSecretOptionsSecretTypePrivateCertConst),
  187. ID: secretName,
  188. })
  189. if err != nil {
  190. return nil, err
  191. }
  192. secret := response.Resources[0].(*sm.SecretResource)
  193. secretData := secret.SecretData.(map[string]interface{})
  194. if val, ok := secretData[ref.Property]; ok {
  195. return []byte(val.(string)), nil
  196. }
  197. return nil, fmt.Errorf("key %s does not exist in secret %s", ref.Property, ref.Key)
  198. }
  199. func getIamCredentialsSecret(ibm *providerIBM, secretName *string) ([]byte, error) {
  200. response, _, err := ibm.IBMClient.GetSecret(
  201. &sm.GetSecretOptions{
  202. SecretType: core.StringPtr(sm.CreateSecretOptionsSecretTypeIamCredentialsConst),
  203. ID: secretName,
  204. })
  205. if err != nil {
  206. return nil, err
  207. }
  208. secret := response.Resources[0].(*sm.SecretResource)
  209. secretData := *secret.APIKey
  210. return []byte(secretData), nil
  211. }
  212. func getUsernamePasswordSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  213. response, _, err := ibm.IBMClient.GetSecret(
  214. &sm.GetSecretOptions{
  215. SecretType: core.StringPtr(sm.CreateSecretOptionsSecretTypeUsernamePasswordConst),
  216. ID: secretName,
  217. })
  218. if err != nil {
  219. return nil, err
  220. }
  221. secret := response.Resources[0].(*sm.SecretResource)
  222. secretData := secret.SecretData.(map[string]interface{})
  223. if val, ok := secretData[ref.Property]; ok {
  224. return []byte(val.(string)), nil
  225. }
  226. return nil, fmt.Errorf("key %s does not exist in secret %s", ref.Property, ref.Key)
  227. }
  228. // Returns a secret of type kv and supports json path.
  229. func getKVSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  230. secret, err := getSecretByType(ibm, secretName, sm.CreateSecretOptionsSecretTypeKvConst)
  231. if err != nil {
  232. return nil, err
  233. }
  234. log.Info("fetching secret", "secretName", secretName, "key", ref.Key)
  235. secretData := secret.SecretData.(map[string]interface{})
  236. payload, ok := secretData["payload"]
  237. if !ok {
  238. return nil, fmt.Errorf("no payload returned for secret %s", ref.Key)
  239. }
  240. payloadJSON := payload
  241. payloadJSONMap, ok := payloadJSON.(map[string]interface{})
  242. if ok {
  243. var payloadJSONByte []byte
  244. payloadJSONByte, err = json.Marshal(payloadJSONMap)
  245. if err != nil {
  246. return nil, fmt.Errorf("marshaling payload from secret failed. %w", err)
  247. }
  248. payloadJSON = string(payloadJSONByte)
  249. }
  250. // no property requested, return the entire payload
  251. if ref.Property == "" {
  252. return []byte(payloadJSON.(string)), nil
  253. }
  254. // returns the requested key
  255. // consider that the key contains a ".". this could be one of 2 options
  256. // a) "." is part of the key name
  257. // b) "." is symbole for JSON path
  258. if ref.Property != "" {
  259. refProperty := ref.Property
  260. // a) "." is part the key name
  261. // escape "."
  262. idx := strings.Index(refProperty, ".")
  263. if idx > 0 {
  264. refProperty = strings.ReplaceAll(refProperty, ".", "\\.")
  265. val := gjson.Get(payloadJSON.(string), refProperty)
  266. if val.Exists() {
  267. return []byte(val.String()), nil
  268. }
  269. }
  270. // b) "." is symbole for JSON path
  271. // try to get value for this path
  272. val := gjson.Get(payloadJSON.(string), ref.Property)
  273. if !val.Exists() {
  274. return nil, fmt.Errorf("key %s does not exist in secret %s", ref.Property, ref.Key)
  275. }
  276. return []byte(val.String()), nil
  277. }
  278. return nil, fmt.Errorf("no property provided for secret %s", ref.Key)
  279. }
  280. func getSecretByType(ibm *providerIBM, secretName *string, secretType string) (*sm.SecretResource, error) {
  281. response, _, err := ibm.IBMClient.GetSecret(
  282. &sm.GetSecretOptions{
  283. SecretType: core.StringPtr(secretType),
  284. ID: secretName,
  285. })
  286. if err != nil {
  287. return nil, err
  288. }
  289. secret := response.Resources[0].(*sm.SecretResource)
  290. return secret, nil
  291. }
  292. func (ibm *providerIBM) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  293. if utils.IsNil(ibm.IBMClient) {
  294. return nil, fmt.Errorf(errUninitalizedIBMProvider)
  295. }
  296. secretType := sm.GetSecretOptionsSecretTypeArbitraryConst
  297. secretName := ref.Key
  298. nameSplitted := strings.Split(secretName, "/")
  299. if len(nameSplitted) > 1 {
  300. secretType = nameSplitted[0]
  301. secretName = nameSplitted[1]
  302. }
  303. switch secretType {
  304. case sm.GetSecretOptionsSecretTypeArbitraryConst:
  305. response, _, err := ibm.IBMClient.GetSecret(
  306. &sm.GetSecretOptions{
  307. SecretType: core.StringPtr(sm.GetSecretOptionsSecretTypeArbitraryConst),
  308. ID: &ref.Key,
  309. })
  310. if err != nil {
  311. return nil, err
  312. }
  313. secret := response.Resources[0].(*sm.SecretResource)
  314. secretData := secret.SecretData.(map[string]interface{})
  315. arbitrarySecretPayload := secretData["payload"].(string)
  316. kv := make(map[string]interface{})
  317. err = json.Unmarshal([]byte(arbitrarySecretPayload), &kv)
  318. if err != nil {
  319. return nil, fmt.Errorf(errJSONSecretUnmarshal, err)
  320. }
  321. secretMap := byteArrayMap(kv)
  322. return secretMap, nil
  323. case sm.CreateSecretOptionsSecretTypeUsernamePasswordConst:
  324. response, _, err := ibm.IBMClient.GetSecret(
  325. &sm.GetSecretOptions{
  326. SecretType: core.StringPtr(sm.CreateSecretOptionsSecretTypeUsernamePasswordConst),
  327. ID: &secretName,
  328. })
  329. if err != nil {
  330. return nil, err
  331. }
  332. secret := response.Resources[0].(*sm.SecretResource)
  333. secretData := secret.SecretData.(map[string]interface{})
  334. secretMap := byteArrayMap(secretData)
  335. return secretMap, nil
  336. case sm.CreateSecretOptionsSecretTypeIamCredentialsConst:
  337. response, _, err := ibm.IBMClient.GetSecret(
  338. &sm.GetSecretOptions{
  339. SecretType: core.StringPtr(sm.CreateSecretOptionsSecretTypeIamCredentialsConst),
  340. ID: &secretName,
  341. })
  342. if err != nil {
  343. return nil, err
  344. }
  345. secret := response.Resources[0].(*sm.SecretResource)
  346. secretData := *secret.APIKey
  347. secretMap := make(map[string][]byte)
  348. secretMap["apikey"] = []byte(secretData)
  349. return secretMap, nil
  350. case sm.CreateSecretOptionsSecretTypeImportedCertConst:
  351. response, _, err := ibm.IBMClient.GetSecret(
  352. &sm.GetSecretOptions{
  353. SecretType: core.StringPtr(sm.CreateSecretOptionsSecretTypeImportedCertConst),
  354. ID: &secretName,
  355. })
  356. if err != nil {
  357. return nil, err
  358. }
  359. secret := response.Resources[0].(*sm.SecretResource)
  360. secretData := secret.SecretData.(map[string]interface{})
  361. secretMap := byteArrayMap(secretData)
  362. return secretMap, nil
  363. case sm.CreateSecretOptionsSecretTypePublicCertConst:
  364. response, _, err := ibm.IBMClient.GetSecret(
  365. &sm.GetSecretOptions{
  366. SecretType: core.StringPtr(sm.CreateSecretOptionsSecretTypePublicCertConst),
  367. ID: &secretName,
  368. })
  369. if err != nil {
  370. return nil, err
  371. }
  372. secret := response.Resources[0].(*sm.SecretResource)
  373. secretData := secret.SecretData.(map[string]interface{})
  374. secretMap := byteArrayMap(secretData)
  375. return secretMap, nil
  376. case sm.CreateSecretOptionsSecretTypePrivateCertConst:
  377. response, _, err := ibm.IBMClient.GetSecret(
  378. &sm.GetSecretOptions{
  379. SecretType: core.StringPtr(sm.CreateSecretOptionsSecretTypePrivateCertConst),
  380. ID: &secretName,
  381. })
  382. if err != nil {
  383. return nil, err
  384. }
  385. secret := response.Resources[0].(*sm.SecretResource)
  386. secretData := secret.SecretData.(map[string]interface{})
  387. secretMap := byteArrayMap(secretData)
  388. return secretMap, nil
  389. case sm.CreateSecretOptionsSecretTypeKvConst:
  390. secret, err := getKVSecret(ibm, &secretName, ref)
  391. if err != nil {
  392. return nil, err
  393. }
  394. m := make(map[string]interface{})
  395. err = json.Unmarshal(secret, &m)
  396. if err != nil {
  397. return nil, err
  398. }
  399. secretMap := byteArrayMap(m)
  400. return secretMap, nil
  401. default:
  402. return nil, fmt.Errorf("unknown secret type %s", secretType)
  403. }
  404. }
  405. func byteArrayMap(secretData map[string]interface{}) map[string][]byte {
  406. var err error
  407. secretMap := make(map[string][]byte)
  408. for k, v := range secretData {
  409. secretMap[k], err = getTypedKey(v)
  410. if err != nil {
  411. return nil
  412. }
  413. }
  414. return secretMap
  415. }
  416. // kudos Vault Provider - convert from various types.
  417. func getTypedKey(v interface{}) ([]byte, error) {
  418. switch t := v.(type) {
  419. case string:
  420. return []byte(t), nil
  421. case map[string]interface{}:
  422. return json.Marshal(t)
  423. case map[string]string:
  424. return json.Marshal(t)
  425. case []byte:
  426. return t, nil
  427. // also covers int and float32 due to json.Marshal
  428. case float64:
  429. return []byte(strconv.FormatFloat(t, 'f', -1, 64)), nil
  430. case bool:
  431. return []byte(strconv.FormatBool(t)), nil
  432. case nil:
  433. return []byte(nil), nil
  434. default:
  435. return nil, fmt.Errorf("secret not in expected format")
  436. }
  437. }
  438. func (ibm *providerIBM) Close(ctx context.Context) error {
  439. return nil
  440. }
  441. func (ibm *providerIBM) Validate() (esv1beta1.ValidationResult, error) {
  442. return esv1beta1.ValidationResultReady, nil
  443. }
  444. func (ibm *providerIBM) ValidateStore(store esv1beta1.GenericStore) error {
  445. storeSpec := store.GetSpec()
  446. ibmSpec := storeSpec.Provider.IBM
  447. if ibmSpec.ServiceURL == nil {
  448. return fmt.Errorf("serviceURL is required")
  449. }
  450. secretRef := ibmSpec.Auth.SecretRef.SecretAPIKey
  451. err := utils.ValidateSecretSelector(store, secretRef)
  452. if err != nil {
  453. return err
  454. }
  455. if secretRef.Name == "" {
  456. return fmt.Errorf("secretAPIKey.name cannot be empty")
  457. }
  458. if secretRef.Key == "" {
  459. return fmt.Errorf("secretAPIKey.key cannot be empty")
  460. }
  461. return nil
  462. }
  463. // Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
  464. func (ibm *providerIBM) Capabilities() esv1beta1.SecretStoreCapabilities {
  465. return esv1beta1.SecretStoreReadOnly
  466. }
  467. func (ibm *providerIBM) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
  468. storeSpec := store.GetSpec()
  469. ibmSpec := storeSpec.Provider.IBM
  470. iStore := &client{
  471. kube: kube,
  472. store: ibmSpec,
  473. namespace: namespace,
  474. storeKind: store.GetObjectKind().GroupVersionKind().Kind,
  475. }
  476. if err := iStore.setAuth(ctx); err != nil {
  477. return nil, err
  478. }
  479. secretsManager, err := sm.NewSecretsManagerV1(&sm.SecretsManagerV1Options{
  480. URL: *storeSpec.Provider.IBM.ServiceURL,
  481. Authenticator: &core.IamAuthenticator{
  482. ApiKey: string(iStore.credentials),
  483. },
  484. })
  485. // Setup retry options, but only if present
  486. if storeSpec.RetrySettings != nil {
  487. var retryAmount int
  488. var retryDuration time.Duration
  489. if storeSpec.RetrySettings.MaxRetries != nil {
  490. retryAmount = int(*storeSpec.RetrySettings.MaxRetries)
  491. } else {
  492. retryAmount = 3
  493. }
  494. if storeSpec.RetrySettings.RetryInterval != nil {
  495. retryDuration, err = time.ParseDuration(*storeSpec.RetrySettings.RetryInterval)
  496. } else {
  497. retryDuration = 5 * time.Second
  498. }
  499. if err == nil {
  500. secretsManager.Service.EnableRetries(retryAmount, retryDuration)
  501. }
  502. }
  503. if err != nil {
  504. return nil, fmt.Errorf(errIBMClient, err)
  505. }
  506. ibm.IBMClient = secretsManager
  507. return ibm, nil
  508. }
  509. func init() {
  510. esv1beta1.Register(&providerIBM{}, &esv1beta1.SecretStoreProvider{
  511. IBM: &esv1beta1.IBMProvider{},
  512. })
  513. }