provider.go 22 KB

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