provider.go 22 KB

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