provider.go 22 KB

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