provider.go 23 KB

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