provider.go 23 KB

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