provider.go 22 KB

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