provider.go 21 KB

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