provider.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  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. "os"
  18. "strconv"
  19. "strings"
  20. "time"
  21. core "github.com/IBM/go-sdk-core/v5/core"
  22. sm "github.com/IBM/secrets-manager-go-sdk/v2/secretsmanagerv2"
  23. gjson "github.com/tidwall/gjson"
  24. corev1 "k8s.io/api/core/v1"
  25. types "k8s.io/apimachinery/pkg/types"
  26. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  27. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  28. "github.com/external-secrets/external-secrets/pkg/provider/metrics"
  29. utils "github.com/external-secrets/external-secrets/pkg/utils"
  30. )
  31. const (
  32. SecretsManagerEndpointEnv = "IBM_SECRETSMANAGER_ENDPOINT"
  33. STSEndpointEnv = "IBM_STS_ENDPOINT"
  34. SSMEndpointEnv = "IBM_SSM_ENDPOINT"
  35. certificateConst = "certificate"
  36. intermediateConst = "intermediate"
  37. privateKeyConst = "private_key"
  38. usernameConst = "username"
  39. passwordConst = "password"
  40. apikeyConst = "apikey"
  41. arbitraryConst = "arbitrary"
  42. errIBMClient = "cannot setup new ibm client: %w"
  43. errIBMCredSecretName = "invalid IBM SecretStore resource: missing IBM APIKey"
  44. errUninitalizedIBMProvider = "provider IBM is not initialized"
  45. errInvalidClusterStoreMissingSKNamespace = "invalid ClusterStore, missing namespace"
  46. errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
  47. errMissingSAK = "missing SecretAccessKey"
  48. errJSONSecretUnmarshal = "unable to unmarshal secret: %w"
  49. errExtractingSecret = "unable to extract the fetched secret %s of type %s"
  50. )
  51. var contextTimeout = time.Minute * 2
  52. // https://github.com/external-secrets/external-secrets/issues/644
  53. var _ esv1beta1.SecretsClient = &providerIBM{}
  54. var _ esv1beta1.Provider = &providerIBM{}
  55. type SecretManagerClient interface {
  56. GetSecretWithContext(ctx context.Context, getSecretOptions *sm.GetSecretOptions) (result sm.SecretIntf, response *core.DetailedResponse, err error)
  57. }
  58. type providerIBM struct {
  59. IBMClient SecretManagerClient
  60. }
  61. type client struct {
  62. kube kclient.Client
  63. store *esv1beta1.IBMProvider
  64. namespace string
  65. storeKind string
  66. credentials []byte
  67. }
  68. func (c *client) setAuth(ctx context.Context) error {
  69. credentialsSecret := &corev1.Secret{}
  70. credentialsSecretName := c.store.Auth.SecretRef.SecretAPIKey.Name
  71. if credentialsSecretName == "" {
  72. return fmt.Errorf(errIBMCredSecretName)
  73. }
  74. objectKey := types.NamespacedName{
  75. Name: credentialsSecretName,
  76. Namespace: c.namespace,
  77. }
  78. // only ClusterStore is allowed to set namespace (and then it's required)
  79. if c.storeKind == esv1beta1.ClusterSecretStoreKind {
  80. if c.store.Auth.SecretRef.SecretAPIKey.Namespace == nil {
  81. return fmt.Errorf(errInvalidClusterStoreMissingSKNamespace)
  82. }
  83. objectKey.Namespace = *c.store.Auth.SecretRef.SecretAPIKey.Namespace
  84. }
  85. err := c.kube.Get(ctx, objectKey, credentialsSecret)
  86. if err != nil {
  87. return fmt.Errorf(errFetchSAKSecret, err)
  88. }
  89. c.credentials = credentialsSecret.Data[c.store.Auth.SecretRef.SecretAPIKey.Key]
  90. if (c.credentials == nil) || (len(c.credentials) == 0) {
  91. return fmt.Errorf(errMissingSAK)
  92. }
  93. return nil
  94. }
  95. func (ibm *providerIBM) DeleteSecret(_ context.Context, _ esv1beta1.PushRemoteRef) error {
  96. return fmt.Errorf("not implemented")
  97. }
  98. // Not Implemented PushSecret.
  99. func (ibm *providerIBM) PushSecret(_ context.Context, _ []byte, _ esv1beta1.PushRemoteRef) error {
  100. return fmt.Errorf("not implemented")
  101. }
  102. // Empty GetAllSecrets.
  103. func (ibm *providerIBM) GetAllSecrets(_ context.Context, _ esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  104. // TO be implemented
  105. return nil, fmt.Errorf("GetAllSecrets not implemented")
  106. }
  107. func (ibm *providerIBM) GetSecret(_ context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  108. if utils.IsNil(ibm.IBMClient) {
  109. return nil, fmt.Errorf(errUninitalizedIBMProvider)
  110. }
  111. secretType := sm.Secret_SecretType_Arbitrary
  112. secretName := ref.Key
  113. nameSplitted := strings.Split(secretName, "/")
  114. if len(nameSplitted) > 1 {
  115. secretType = nameSplitted[0]
  116. secretName = nameSplitted[1]
  117. }
  118. switch secretType {
  119. case sm.Secret_SecretType_Arbitrary:
  120. return getArbitrarySecret(ibm, &secretName)
  121. case sm.Secret_SecretType_UsernamePassword:
  122. if ref.Property == "" {
  123. return nil, fmt.Errorf("remoteRef.property required for secret type username_password")
  124. }
  125. return getUsernamePasswordSecret(ibm, &secretName, ref)
  126. case sm.Secret_SecretType_IamCredentials:
  127. return getIamCredentialsSecret(ibm, &secretName)
  128. case sm.Secret_SecretType_ImportedCert:
  129. if ref.Property == "" {
  130. return nil, fmt.Errorf("remoteRef.property required for secret type imported_cert")
  131. }
  132. return getImportCertSecret(ibm, &secretName, ref)
  133. case sm.Secret_SecretType_PublicCert:
  134. if ref.Property == "" {
  135. return nil, fmt.Errorf("remoteRef.property required for secret type public_cert")
  136. }
  137. return getPublicCertSecret(ibm, &secretName, ref)
  138. case sm.Secret_SecretType_PrivateCert:
  139. if ref.Property == "" {
  140. return nil, fmt.Errorf("remoteRef.property required for secret type private_cert")
  141. }
  142. return getPrivateCertSecret(ibm, &secretName, ref)
  143. case sm.Secret_SecretType_Kv:
  144. return getKVSecret(ibm, &secretName, ref)
  145. default:
  146. return nil, fmt.Errorf("unknown secret type %s", secretType)
  147. }
  148. }
  149. func getArbitrarySecret(ibm *providerIBM, secretName *string) ([]byte, error) {
  150. response, err := getSecretData(ibm, secretName)
  151. if err != nil {
  152. return nil, err
  153. }
  154. secret, ok := response.(*sm.ArbitrarySecret)
  155. if !ok {
  156. return nil, fmt.Errorf(errExtractingSecret, *secretName, sm.Secret_SecretType_Arbitrary)
  157. }
  158. return []byte(*secret.Payload), nil
  159. }
  160. func getImportCertSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  161. response, err := getSecretData(ibm, secretName)
  162. if err != nil {
  163. return nil, err
  164. }
  165. secret, ok := response.(*sm.ImportedCertificate)
  166. if !ok {
  167. return nil, fmt.Errorf(errExtractingSecret, *secretName, sm.Secret_SecretType_ImportedCert)
  168. }
  169. switch ref.Property {
  170. case certificateConst:
  171. return []byte(*secret.Certificate), nil
  172. case intermediateConst:
  173. return []byte(*secret.Intermediate), nil
  174. case privateKeyConst:
  175. return []byte(*secret.PrivateKey), nil
  176. default:
  177. return nil, fmt.Errorf("unknown property type %s", ref.Property)
  178. }
  179. }
  180. func getPublicCertSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  181. response, err := getSecretData(ibm, secretName)
  182. if err != nil {
  183. return nil, err
  184. }
  185. secret, ok := response.(*sm.PublicCertificate)
  186. if !ok {
  187. return nil, fmt.Errorf(errExtractingSecret, *secretName, sm.Secret_SecretType_PublicCert)
  188. }
  189. switch ref.Property {
  190. case certificateConst:
  191. return []byte(*secret.Certificate), nil
  192. case intermediateConst:
  193. return []byte(*secret.Intermediate), nil
  194. case privateKeyConst:
  195. return []byte(*secret.PrivateKey), nil
  196. default:
  197. return nil, fmt.Errorf("unknown property type %s", ref.Property)
  198. }
  199. }
  200. func getPrivateCertSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  201. response, err := getSecretData(ibm, secretName)
  202. if err != nil {
  203. return nil, err
  204. }
  205. secret, ok := response.(*sm.PrivateCertificate)
  206. if !ok {
  207. return nil, fmt.Errorf(errExtractingSecret, *secretName, sm.Secret_SecretType_PrivateCert)
  208. }
  209. switch ref.Property {
  210. case certificateConst:
  211. return []byte(*secret.Certificate), nil
  212. case privateKeyConst:
  213. return []byte(*secret.PrivateKey), nil
  214. default:
  215. return nil, fmt.Errorf("unknown property type %s", ref.Property)
  216. }
  217. }
  218. func getIamCredentialsSecret(ibm *providerIBM, secretName *string) ([]byte, error) {
  219. response, err := getSecretData(ibm, secretName)
  220. if err != nil {
  221. return nil, err
  222. }
  223. secret, ok := response.(*sm.IAMCredentialsSecret)
  224. if !ok {
  225. return nil, fmt.Errorf(errExtractingSecret, *secretName, sm.Secret_SecretType_IamCredentials)
  226. }
  227. return []byte(*secret.ApiKey), nil
  228. }
  229. func getUsernamePasswordSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  230. response, err := getSecretData(ibm, secretName)
  231. if err != nil {
  232. return nil, err
  233. }
  234. secret, ok := response.(*sm.UsernamePasswordSecret)
  235. if !ok {
  236. return nil, fmt.Errorf(errExtractingSecret, *secretName, sm.Secret_SecretType_UsernamePassword)
  237. }
  238. switch ref.Property {
  239. case "username":
  240. return []byte(*secret.Username), nil
  241. case "password":
  242. return []byte(*secret.Password), nil
  243. default:
  244. return nil, fmt.Errorf("unknown property type %s", ref.Property)
  245. }
  246. }
  247. // Returns a secret of type kv and supports json path.
  248. func getKVSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  249. response, err := getSecretData(ibm, secretName)
  250. if err != nil {
  251. return nil, err
  252. }
  253. secret, ok := response.(*sm.KVSecret)
  254. if !ok {
  255. return nil, fmt.Errorf(errExtractingSecret, *secretName, sm.Secret_SecretType_Kv)
  256. }
  257. payloadJSONByte, err := json.Marshal(secret.Data)
  258. if err != nil {
  259. return nil, fmt.Errorf("marshaling payload from secret failed. %w", err)
  260. }
  261. payloadJSON := string(payloadJSONByte)
  262. // no property requested, return the entire payload
  263. if ref.Property == "" {
  264. return []byte(payloadJSON), nil
  265. }
  266. // returns the requested key
  267. // consider that the key contains a ".". this could be one of 2 options
  268. // a) "." is part of the key name
  269. // b) "." is symbole for JSON path
  270. if ref.Property != "" {
  271. refProperty := ref.Property
  272. // a) "." is part the key name
  273. // escape "."
  274. idx := strings.Index(refProperty, ".")
  275. if idx > 0 {
  276. refProperty = strings.ReplaceAll(refProperty, ".", "\\.")
  277. val := gjson.Get(payloadJSON, refProperty)
  278. if val.Exists() {
  279. return []byte(val.String()), nil
  280. }
  281. }
  282. // b) "." is symbole for JSON path
  283. // try to get value for this path
  284. val := gjson.Get(payloadJSON, ref.Property)
  285. if !val.Exists() {
  286. return nil, fmt.Errorf("key %s does not exist in secret %s", ref.Property, ref.Key)
  287. }
  288. return []byte(val.String()), nil
  289. }
  290. return nil, fmt.Errorf("no property provided for secret %s", ref.Key)
  291. }
  292. func getSecretData(ibm *providerIBM, secretName *string) (sm.SecretIntf, error) {
  293. ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
  294. defer cancel()
  295. response, _, err := ibm.IBMClient.GetSecretWithContext(
  296. ctx,
  297. &sm.GetSecretOptions{
  298. ID: secretName,
  299. })
  300. metrics.ObserveAPICall(metrics.ProviderIBMSM, metrics.CallIBMSMGetSecret, err)
  301. if err != nil {
  302. return nil, err
  303. }
  304. return response, nil
  305. }
  306. func (ibm *providerIBM) GetSecretMap(_ context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  307. if utils.IsNil(ibm.IBMClient) {
  308. return nil, fmt.Errorf(errUninitalizedIBMProvider)
  309. }
  310. secretType := sm.Secret_SecretType_Arbitrary
  311. secretName := ref.Key
  312. nameSplitted := strings.Split(secretName, "/")
  313. if len(nameSplitted) > 1 {
  314. secretType = nameSplitted[0]
  315. secretName = nameSplitted[1]
  316. }
  317. secretMap := make(map[string][]byte)
  318. response, err := getSecretData(ibm, &secretName)
  319. if err != nil {
  320. return nil, err
  321. }
  322. switch secretType {
  323. case sm.Secret_SecretType_Arbitrary:
  324. secretData, ok := response.(*sm.ArbitrarySecret)
  325. if !ok {
  326. return nil, fmt.Errorf(errExtractingSecret, secretName, sm.Secret_SecretType_Arbitrary)
  327. }
  328. secretMap[arbitraryConst] = []byte(*secretData.Payload)
  329. return secretMap, nil
  330. case sm.Secret_SecretType_UsernamePassword:
  331. secretData, ok := response.(*sm.UsernamePasswordSecret)
  332. if !ok {
  333. return nil, fmt.Errorf(errExtractingSecret, secretName, sm.Secret_SecretType_UsernamePassword)
  334. }
  335. secretMap[usernameConst] = []byte(*secretData.Username)
  336. secretMap[passwordConst] = []byte(*secretData.Password)
  337. return secretMap, nil
  338. case sm.Secret_SecretType_IamCredentials:
  339. secretData, ok := response.(*sm.IAMCredentialsSecret)
  340. if !ok {
  341. return nil, fmt.Errorf(errExtractingSecret, secretName, sm.Secret_SecretType_IamCredentials)
  342. }
  343. secretMap[apikeyConst] = []byte(*secretData.ApiKey)
  344. return secretMap, nil
  345. case sm.Secret_SecretType_ImportedCert:
  346. secretData, ok := response.(*sm.ImportedCertificate)
  347. if !ok {
  348. return nil, fmt.Errorf(errExtractingSecret, secretName, sm.Secret_SecretType_ImportedCert)
  349. }
  350. secretMap[certificateConst] = []byte(*secretData.Certificate)
  351. secretMap[intermediateConst] = []byte(*secretData.Intermediate)
  352. secretMap[privateKeyConst] = []byte(*secretData.PrivateKey)
  353. return secretMap, nil
  354. case sm.Secret_SecretType_PublicCert:
  355. secretData, ok := response.(*sm.PublicCertificate)
  356. if !ok {
  357. return nil, fmt.Errorf(errExtractingSecret, secretName, sm.Secret_SecretType_PublicCert)
  358. }
  359. secretMap[certificateConst] = []byte(*secretData.Certificate)
  360. secretMap[intermediateConst] = []byte(*secretData.Intermediate)
  361. secretMap[privateKeyConst] = []byte(*secretData.PrivateKey)
  362. return secretMap, nil
  363. case sm.Secret_SecretType_PrivateCert:
  364. secretData, ok := response.(*sm.PrivateCertificate)
  365. if !ok {
  366. return nil, fmt.Errorf(errExtractingSecret, secretName, sm.Secret_SecretType_PrivateCert)
  367. }
  368. secretMap[certificateConst] = []byte(*secretData.Certificate)
  369. secretMap[privateKeyConst] = []byte(*secretData.PrivateKey)
  370. return secretMap, nil
  371. case sm.Secret_SecretType_Kv:
  372. secret, err := getKVSecret(ibm, &secretName, ref)
  373. if err != nil {
  374. return nil, err
  375. }
  376. m := make(map[string]interface{})
  377. err = json.Unmarshal(secret, &m)
  378. if err != nil {
  379. return nil, fmt.Errorf(errJSONSecretUnmarshal, err)
  380. }
  381. secretMap := byteArrayMap(m)
  382. return secretMap, nil
  383. default:
  384. return nil, fmt.Errorf("unknown secret type %s", secretType)
  385. }
  386. }
  387. func byteArrayMap(secretData map[string]interface{}) map[string][]byte {
  388. var err error
  389. secretMap := make(map[string][]byte)
  390. for k, v := range secretData {
  391. secretMap[k], err = getTypedKey(v)
  392. if err != nil {
  393. return nil
  394. }
  395. }
  396. return secretMap
  397. }
  398. // kudos Vault Provider - convert from various types.
  399. func getTypedKey(v interface{}) ([]byte, error) {
  400. switch t := v.(type) {
  401. case string:
  402. return []byte(t), nil
  403. case map[string]interface{}:
  404. return json.Marshal(t)
  405. case map[string]string:
  406. return json.Marshal(t)
  407. case []byte:
  408. return t, nil
  409. // also covers int and float32 due to json.Marshal
  410. case float64:
  411. return []byte(strconv.FormatFloat(t, 'f', -1, 64)), nil
  412. case bool:
  413. return []byte(strconv.FormatBool(t)), nil
  414. case nil:
  415. return []byte(nil), nil
  416. default:
  417. return nil, fmt.Errorf("secret not in expected format")
  418. }
  419. }
  420. func (ibm *providerIBM) Close(_ context.Context) error {
  421. return nil
  422. }
  423. func (ibm *providerIBM) Validate() (esv1beta1.ValidationResult, error) {
  424. return esv1beta1.ValidationResultReady, nil
  425. }
  426. func (ibm *providerIBM) ValidateStore(store esv1beta1.GenericStore) error {
  427. storeSpec := store.GetSpec()
  428. ibmSpec := storeSpec.Provider.IBM
  429. if ibmSpec.ServiceURL == nil {
  430. return fmt.Errorf("serviceURL is required")
  431. }
  432. containerRef := ibmSpec.Auth.ContainerAuth
  433. secretKeyRef := ibmSpec.Auth.SecretRef.SecretAPIKey
  434. if utils.IsNil(containerRef.Profile) || (containerRef.Profile == "") {
  435. // proceed with API Key Auth validation
  436. err := utils.ValidateSecretSelector(store, secretKeyRef)
  437. if err != nil {
  438. return err
  439. }
  440. if secretKeyRef.Name == "" {
  441. return fmt.Errorf("secretAPIKey.name cannot be empty")
  442. }
  443. if secretKeyRef.Key == "" {
  444. return fmt.Errorf("secretAPIKey.key cannot be empty")
  445. }
  446. } else {
  447. // proceed with container auth
  448. if containerRef.TokenLocation == "" {
  449. containerRef.TokenLocation = "/var/run/secrets/tokens/vault-token"
  450. }
  451. if _, err := os.Open(containerRef.TokenLocation); err != nil {
  452. return fmt.Errorf("cannot read container auth token %s. %w", containerRef.TokenLocation, err)
  453. }
  454. }
  455. return nil
  456. }
  457. // Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
  458. func (ibm *providerIBM) Capabilities() esv1beta1.SecretStoreCapabilities {
  459. return esv1beta1.SecretStoreReadOnly
  460. }
  461. func (ibm *providerIBM) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
  462. storeSpec := store.GetSpec()
  463. ibmSpec := storeSpec.Provider.IBM
  464. iStore := &client{
  465. kube: kube,
  466. store: ibmSpec,
  467. namespace: namespace,
  468. storeKind: store.GetObjectKind().GroupVersionKind().Kind,
  469. }
  470. var err error
  471. var secretsManager *sm.SecretsManagerV2
  472. containerAuthProfile := iStore.store.Auth.ContainerAuth.Profile
  473. if containerAuthProfile != "" {
  474. // container-based auth
  475. containerAuthToken := iStore.store.Auth.ContainerAuth.TokenLocation
  476. containerAuthEndpoint := iStore.store.Auth.ContainerAuth.IAMEndpoint
  477. if containerAuthToken == "" {
  478. // API default path
  479. containerAuthToken = "/var/run/secrets/tokens/vault-token"
  480. }
  481. if containerAuthEndpoint == "" {
  482. // API default path
  483. containerAuthEndpoint = "https://iam.cloud.ibm.com"
  484. }
  485. authenticator, err := core.NewContainerAuthenticatorBuilder().
  486. SetIAMProfileName(containerAuthProfile).
  487. SetCRTokenFilename(containerAuthToken).
  488. SetURL(containerAuthEndpoint).
  489. Build()
  490. if err != nil {
  491. return nil, fmt.Errorf(errIBMClient, err)
  492. }
  493. secretsManager, err = sm.NewSecretsManagerV2(&sm.SecretsManagerV2Options{
  494. URL: *storeSpec.Provider.IBM.ServiceURL,
  495. Authenticator: authenticator,
  496. })
  497. if err != nil {
  498. return nil, fmt.Errorf(errIBMClient, err)
  499. }
  500. } else {
  501. // API Key-based auth
  502. if err := iStore.setAuth(ctx); err != nil {
  503. return nil, err
  504. }
  505. secretsManager, err = sm.NewSecretsManagerV2(&sm.SecretsManagerV2Options{
  506. URL: *storeSpec.Provider.IBM.ServiceURL,
  507. Authenticator: &core.IamAuthenticator{
  508. ApiKey: string(iStore.credentials),
  509. },
  510. })
  511. }
  512. // Setup retry options, but only if present
  513. if storeSpec.RetrySettings != nil {
  514. var retryAmount int
  515. var retryDuration time.Duration
  516. if storeSpec.RetrySettings.MaxRetries != nil {
  517. retryAmount = int(*storeSpec.RetrySettings.MaxRetries)
  518. } else {
  519. retryAmount = 3
  520. }
  521. if storeSpec.RetrySettings.RetryInterval != nil {
  522. retryDuration, err = time.ParseDuration(*storeSpec.RetrySettings.RetryInterval)
  523. } else {
  524. retryDuration = 5 * time.Second
  525. }
  526. if err == nil {
  527. secretsManager.Service.EnableRetries(retryAmount, retryDuration)
  528. }
  529. }
  530. if err != nil {
  531. return nil, fmt.Errorf(errIBMClient, err)
  532. }
  533. ibm.IBMClient = secretsManager
  534. return ibm, nil
  535. }
  536. func init() {
  537. esv1beta1.Register(&providerIBM{}, &esv1beta1.SecretStoreProvider{
  538. IBM: &esv1beta1.IBMProvider{},
  539. })
  540. }