provider.go 19 KB

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