provider.go 21 KB

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