provider.go 23 KB

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