provider.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  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. "strconv"
  19. "strings"
  20. "time"
  21. core "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. gjson "github.com/tidwall/gjson"
  25. corev1 "k8s.io/api/core/v1"
  26. types "k8s.io/apimachinery/pkg/types"
  27. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  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. utils "github.com/external-secrets/external-secrets/pkg/utils"
  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. arbitraryConst = "arbitrary"
  44. errIBMClient = "cannot setup new ibm client: %w"
  45. errIBMCredSecretName = "invalid IBM SecretStore resource: missing IBM APIKey"
  46. errUninitalizedIBMProvider = "provider IBM is not initialized"
  47. errInvalidClusterStoreMissingSKNamespace = "invalid ClusterStore, missing namespace"
  48. errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
  49. errMissingSAK = "missing SecretAccessKey"
  50. errJSONSecretUnmarshal = "unable to unmarshal secret: %w"
  51. errExtractingSecret = "unable to extract the fetched secret %s of type %s while performing %s"
  52. defaultCacheSize = 100
  53. defaultCacheExpiry = 1 * time.Hour
  54. )
  55. var contextTimeout = time.Minute * 2
  56. // https://github.com/external-secrets/external-secrets/issues/644
  57. var _ esv1beta1.SecretsClient = &providerIBM{}
  58. var _ esv1beta1.Provider = &providerIBM{}
  59. type SecretManagerClient interface {
  60. GetSecretWithContext(ctx context.Context, getSecretOptions *sm.GetSecretOptions) (result sm.SecretIntf, response *core.DetailedResponse, err error)
  61. ListSecretsWithContext(ctx context.Context, listSecretsOptions *sm.ListSecretsOptions) (result *sm.SecretMetadataPaginatedCollection, response *core.DetailedResponse, err error)
  62. }
  63. type providerIBM struct {
  64. IBMClient SecretManagerClient
  65. cache cacheIntf
  66. }
  67. type client struct {
  68. kube kclient.Client
  69. store *esv1beta1.IBMProvider
  70. namespace string
  71. storeKind string
  72. credentials []byte
  73. }
  74. func (c *client) setAuth(ctx context.Context) error {
  75. credentialsSecret := &corev1.Secret{}
  76. credentialsSecretName := c.store.Auth.SecretRef.SecretAPIKey.Name
  77. if credentialsSecretName == "" {
  78. return fmt.Errorf(errIBMCredSecretName)
  79. }
  80. objectKey := types.NamespacedName{
  81. Name: credentialsSecretName,
  82. Namespace: c.namespace,
  83. }
  84. // only ClusterStore is allowed to set namespace (and then it's required)
  85. if c.storeKind == esv1beta1.ClusterSecretStoreKind {
  86. if c.store.Auth.SecretRef.SecretAPIKey.Namespace == nil {
  87. return fmt.Errorf(errInvalidClusterStoreMissingSKNamespace)
  88. }
  89. objectKey.Namespace = *c.store.Auth.SecretRef.SecretAPIKey.Namespace
  90. }
  91. err := c.kube.Get(ctx, objectKey, credentialsSecret)
  92. if err != nil {
  93. return fmt.Errorf(errFetchSAKSecret, err)
  94. }
  95. c.credentials = credentialsSecret.Data[c.store.Auth.SecretRef.SecretAPIKey.Key]
  96. if (c.credentials == nil) || (len(c.credentials) == 0) {
  97. return fmt.Errorf(errMissingSAK)
  98. }
  99. return nil
  100. }
  101. func (ibm *providerIBM) DeleteSecret(_ context.Context, _ esv1beta1.PushRemoteRef) error {
  102. return fmt.Errorf("not implemented")
  103. }
  104. // Not Implemented PushSecret.
  105. func (ibm *providerIBM) PushSecret(_ context.Context, _ []byte, _ esv1beta1.PushRemoteRef) error {
  106. return fmt.Errorf("not implemented")
  107. }
  108. // Empty GetAllSecrets.
  109. func (ibm *providerIBM) GetAllSecrets(_ context.Context, _ esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  110. // TO be implemented
  111. return nil, fmt.Errorf("GetAllSecrets not implemented")
  112. }
  113. func (ibm *providerIBM) GetSecret(_ context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  114. if utils.IsNil(ibm.IBMClient) {
  115. return nil, fmt.Errorf(errUninitalizedIBMProvider)
  116. }
  117. secretType := sm.Secret_SecretType_Arbitrary
  118. secretName := ref.Key
  119. nameSplitted := strings.Split(secretName, "/")
  120. if len(nameSplitted) > 1 {
  121. secretType = nameSplitted[0]
  122. secretName = nameSplitted[1]
  123. }
  124. switch secretType {
  125. case sm.Secret_SecretType_Arbitrary:
  126. return getArbitrarySecret(ibm, &secretName)
  127. case sm.Secret_SecretType_UsernamePassword:
  128. if ref.Property == "" {
  129. return nil, fmt.Errorf("remoteRef.property required for secret type username_password")
  130. }
  131. return getUsernamePasswordSecret(ibm, &secretName, ref)
  132. case sm.Secret_SecretType_IamCredentials:
  133. return getIamCredentialsSecret(ibm, &secretName)
  134. case sm.Secret_SecretType_ImportedCert:
  135. if ref.Property == "" {
  136. return nil, fmt.Errorf("remoteRef.property required for secret type imported_cert")
  137. }
  138. return getImportCertSecret(ibm, &secretName, ref)
  139. case sm.Secret_SecretType_PublicCert:
  140. if ref.Property == "" {
  141. return nil, fmt.Errorf("remoteRef.property required for secret type public_cert")
  142. }
  143. return getPublicCertSecret(ibm, &secretName, ref)
  144. case sm.Secret_SecretType_PrivateCert:
  145. if ref.Property == "" {
  146. return nil, fmt.Errorf("remoteRef.property required for secret type private_cert")
  147. }
  148. return getPrivateCertSecret(ibm, &secretName, ref)
  149. case sm.Secret_SecretType_Kv:
  150. return getKVSecret(ibm, &secretName, ref)
  151. default:
  152. return nil, fmt.Errorf("unknown secret type %s", secretType)
  153. }
  154. }
  155. func getArbitrarySecret(ibm *providerIBM, secretName *string) ([]byte, error) {
  156. response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_Arbitrary)
  157. if err != nil {
  158. return nil, err
  159. }
  160. secret, ok := response.(*sm.ArbitrarySecret)
  161. if !ok {
  162. return nil, fmt.Errorf(errExtractingSecret, *secretName, sm.Secret_SecretType_Arbitrary, "getArbitrarySecret")
  163. }
  164. return []byte(*secret.Payload), nil
  165. }
  166. func getImportCertSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  167. response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_ImportedCert)
  168. if err != nil {
  169. return nil, err
  170. }
  171. secret, ok := response.(*sm.ImportedCertificate)
  172. if !ok {
  173. return nil, fmt.Errorf(errExtractingSecret, *secretName, sm.Secret_SecretType_ImportedCert, "getImportCertSecret")
  174. }
  175. switch ref.Property {
  176. case certificateConst:
  177. return []byte(*secret.Certificate), nil
  178. case intermediateConst:
  179. return []byte(*secret.Intermediate), nil
  180. case privateKeyConst:
  181. return []byte(*secret.PrivateKey), nil
  182. default:
  183. return nil, fmt.Errorf("unknown property type %s", ref.Property)
  184. }
  185. }
  186. func getPublicCertSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  187. response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_PublicCert)
  188. if err != nil {
  189. return nil, err
  190. }
  191. secret, ok := response.(*sm.PublicCertificate)
  192. if !ok {
  193. return nil, fmt.Errorf(errExtractingSecret, *secretName, sm.Secret_SecretType_PublicCert, "getPublicCertSecret")
  194. }
  195. switch ref.Property {
  196. case certificateConst:
  197. return []byte(*secret.Certificate), nil
  198. case intermediateConst:
  199. return []byte(*secret.Intermediate), nil
  200. case privateKeyConst:
  201. return []byte(*secret.PrivateKey), nil
  202. default:
  203. return nil, fmt.Errorf("unknown property type %s", ref.Property)
  204. }
  205. }
  206. func getPrivateCertSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  207. response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_PrivateCert)
  208. if err != nil {
  209. return nil, err
  210. }
  211. secret, ok := response.(*sm.PrivateCertificate)
  212. if !ok {
  213. return nil, fmt.Errorf(errExtractingSecret, *secretName, sm.Secret_SecretType_PrivateCert, "getPrivateCertSecret")
  214. }
  215. switch ref.Property {
  216. case certificateConst:
  217. return []byte(*secret.Certificate), nil
  218. case privateKeyConst:
  219. return []byte(*secret.PrivateKey), nil
  220. default:
  221. return nil, fmt.Errorf("unknown property type %s", ref.Property)
  222. }
  223. }
  224. func getIamCredentialsSecret(ibm *providerIBM, secretName *string) ([]byte, error) {
  225. response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_IamCredentials)
  226. if err != nil {
  227. return nil, err
  228. }
  229. secret, ok := response.(*sm.IAMCredentialsSecret)
  230. if !ok {
  231. return nil, fmt.Errorf(errExtractingSecret, *secretName, sm.Secret_SecretType_IamCredentials, "getIamCredentialsSecret")
  232. }
  233. return []byte(*secret.ApiKey), nil
  234. }
  235. func getUsernamePasswordSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  236. response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_UsernamePassword)
  237. if err != nil {
  238. return nil, err
  239. }
  240. secret, ok := response.(*sm.UsernamePasswordSecret)
  241. if !ok {
  242. return nil, fmt.Errorf(errExtractingSecret, *secretName, sm.Secret_SecretType_UsernamePassword, "getUsernamePasswordSecret")
  243. }
  244. switch ref.Property {
  245. case "username":
  246. return []byte(*secret.Username), nil
  247. case "password":
  248. return []byte(*secret.Password), nil
  249. default:
  250. return nil, fmt.Errorf("unknown property type %s", ref.Property)
  251. }
  252. }
  253. // Returns a secret of type kv and supports json path.
  254. func getKVSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  255. response, err := getSecretData(ibm, secretName, sm.Secret_SecretType_Kv)
  256. if err != nil {
  257. return nil, err
  258. }
  259. secret, ok := response.(*sm.KVSecret)
  260. if !ok {
  261. return nil, fmt.Errorf(errExtractingSecret, *secretName, sm.Secret_SecretType_Kv, "getKVSecret")
  262. }
  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 string) (sm.SecretIntf, error) {
  299. var givenName *string
  300. var cachedKey string
  301. // parse given secretName for a uuid or a secret name
  302. _, err := uuid.Parse(*secretName)
  303. if err != nil {
  304. givenName = secretName
  305. cachedKey = fmt.Sprintf("%s/%s", secretType, *givenName)
  306. isCached, cacheData := ibm.cache.GetData(cachedKey)
  307. tmp := string(cacheData)
  308. cachedName := &tmp
  309. if isCached && *cachedName != "" {
  310. secretName = cachedName
  311. } else {
  312. secretName, err = findSecretByName(ibm, givenName, secretType)
  313. if err != nil {
  314. return nil, err
  315. }
  316. ibm.cache.PutData(cachedKey, []byte(*secretName))
  317. }
  318. }
  319. ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
  320. defer cancel()
  321. response, _, err := ibm.IBMClient.GetSecretWithContext(
  322. ctx,
  323. &sm.GetSecretOptions{
  324. ID: secretName,
  325. })
  326. metrics.ObserveAPICall(constants.ProviderIBMSM, constants.CallIBMSMGetSecret, err)
  327. if err != nil {
  328. return nil, err
  329. }
  330. return response, nil
  331. }
  332. func findSecretByName(ibm *providerIBM, secretName *string, secretType string) (*string, error) {
  333. var secretID *string
  334. ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
  335. defer cancel()
  336. response, _, err := ibm.IBMClient.ListSecretsWithContext(ctx,
  337. &sm.ListSecretsOptions{
  338. Search: secretName,
  339. })
  340. metrics.ObserveAPICall(constants.ProviderIBMSM, constants.CallIBMSMListSecrets, err)
  341. if err != nil {
  342. return nil, err
  343. }
  344. found := 0
  345. for _, r := range response.Secrets {
  346. foundsecretID, foundSecretName, err := extractSecretMetadata(r, secretName, secretType)
  347. if err == nil {
  348. if *foundSecretName == *secretName {
  349. found++
  350. secretID = foundsecretID
  351. }
  352. }
  353. }
  354. if found == 0 {
  355. return nil, fmt.Errorf("failed to find a secret for the given secretName %s", *secretName)
  356. }
  357. if found > 1 {
  358. return nil, fmt.Errorf("found more than one secret matching for the given secretName %s, cannot proceed further", *secretName)
  359. }
  360. return secretID, nil
  361. }
  362. func (ibm *providerIBM) GetSecretMap(_ context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  363. if utils.IsNil(ibm.IBMClient) {
  364. return nil, fmt.Errorf(errUninitalizedIBMProvider)
  365. }
  366. secretType := sm.Secret_SecretType_Arbitrary
  367. secretName := ref.Key
  368. nameSplitted := strings.Split(secretName, "/")
  369. if len(nameSplitted) > 1 {
  370. secretType = nameSplitted[0]
  371. secretName = nameSplitted[1]
  372. }
  373. secretMap := make(map[string][]byte)
  374. response, err := getSecretData(ibm, &secretName, secretType)
  375. if err != nil {
  376. return nil, err
  377. }
  378. switch secretType {
  379. case sm.Secret_SecretType_Arbitrary:
  380. secretData, ok := response.(*sm.ArbitrarySecret)
  381. if !ok {
  382. return nil, fmt.Errorf(errExtractingSecret, secretName, sm.Secret_SecretType_Arbitrary, "GetSecretMap")
  383. }
  384. secretMap[arbitraryConst] = []byte(*secretData.Payload)
  385. return secretMap, nil
  386. case sm.Secret_SecretType_UsernamePassword:
  387. secretData, ok := response.(*sm.UsernamePasswordSecret)
  388. if !ok {
  389. return nil, fmt.Errorf(errExtractingSecret, secretName, sm.Secret_SecretType_UsernamePassword, "GetSecretMap")
  390. }
  391. secretMap[usernameConst] = []byte(*secretData.Username)
  392. secretMap[passwordConst] = []byte(*secretData.Password)
  393. return secretMap, nil
  394. case sm.Secret_SecretType_IamCredentials:
  395. secretData, ok := response.(*sm.IAMCredentialsSecret)
  396. if !ok {
  397. return nil, fmt.Errorf(errExtractingSecret, secretName, sm.Secret_SecretType_IamCredentials, "GetSecretMap")
  398. }
  399. secretMap[apikeyConst] = []byte(*secretData.ApiKey)
  400. return secretMap, nil
  401. case sm.Secret_SecretType_ImportedCert:
  402. secretData, ok := response.(*sm.ImportedCertificate)
  403. if !ok {
  404. return nil, fmt.Errorf(errExtractingSecret, secretName, sm.Secret_SecretType_ImportedCert, "GetSecretMap")
  405. }
  406. secretMap[certificateConst] = []byte(*secretData.Certificate)
  407. secretMap[intermediateConst] = []byte(*secretData.Intermediate)
  408. secretMap[privateKeyConst] = []byte(*secretData.PrivateKey)
  409. return secretMap, nil
  410. case sm.Secret_SecretType_PublicCert:
  411. secretData, ok := response.(*sm.PublicCertificate)
  412. if !ok {
  413. return nil, fmt.Errorf(errExtractingSecret, secretName, sm.Secret_SecretType_PublicCert, "GetSecretMap")
  414. }
  415. secretMap[certificateConst] = []byte(*secretData.Certificate)
  416. secretMap[intermediateConst] = []byte(*secretData.Intermediate)
  417. secretMap[privateKeyConst] = []byte(*secretData.PrivateKey)
  418. return secretMap, nil
  419. case sm.Secret_SecretType_PrivateCert:
  420. secretData, ok := response.(*sm.PrivateCertificate)
  421. if !ok {
  422. return nil, fmt.Errorf(errExtractingSecret, secretName, sm.Secret_SecretType_PrivateCert, "GetSecretMap")
  423. }
  424. secretMap[certificateConst] = []byte(*secretData.Certificate)
  425. secretMap[privateKeyConst] = []byte(*secretData.PrivateKey)
  426. return secretMap, nil
  427. case sm.Secret_SecretType_Kv:
  428. secret, err := getKVSecret(ibm, &secretName, ref)
  429. if err != nil {
  430. return nil, err
  431. }
  432. m := make(map[string]interface{})
  433. err = json.Unmarshal(secret, &m)
  434. if err != nil {
  435. return nil, fmt.Errorf(errJSONSecretUnmarshal, err)
  436. }
  437. secretMap := byteArrayMap(m)
  438. return secretMap, nil
  439. default:
  440. return nil, fmt.Errorf("unknown secret type %s", secretType)
  441. }
  442. }
  443. func byteArrayMap(secretData map[string]interface{}) map[string][]byte {
  444. var err error
  445. secretMap := make(map[string][]byte)
  446. for k, v := range secretData {
  447. secretMap[k], err = getTypedKey(v)
  448. if err != nil {
  449. return nil
  450. }
  451. }
  452. return secretMap
  453. }
  454. // kudos Vault Provider - convert from various types.
  455. func getTypedKey(v interface{}) ([]byte, error) {
  456. switch t := v.(type) {
  457. case string:
  458. return []byte(t), nil
  459. case map[string]interface{}:
  460. return json.Marshal(t)
  461. case map[string]string:
  462. return json.Marshal(t)
  463. case []byte:
  464. return t, nil
  465. // also covers int and float32 due to json.Marshal
  466. case float64:
  467. return []byte(strconv.FormatFloat(t, 'f', -1, 64)), nil
  468. case bool:
  469. return []byte(strconv.FormatBool(t)), nil
  470. case nil:
  471. return []byte(nil), nil
  472. default:
  473. return nil, fmt.Errorf("secret not in expected format")
  474. }
  475. }
  476. func (ibm *providerIBM) Close(_ context.Context) error {
  477. return nil
  478. }
  479. func (ibm *providerIBM) Validate() (esv1beta1.ValidationResult, error) {
  480. return esv1beta1.ValidationResultReady, nil
  481. }
  482. func (ibm *providerIBM) ValidateStore(store esv1beta1.GenericStore) error {
  483. storeSpec := store.GetSpec()
  484. ibmSpec := storeSpec.Provider.IBM
  485. if ibmSpec.ServiceURL == nil {
  486. return fmt.Errorf("serviceURL is required")
  487. }
  488. containerRef := ibmSpec.Auth.ContainerAuth
  489. secretKeyRef := ibmSpec.Auth.SecretRef.SecretAPIKey
  490. if utils.IsNil(containerRef.Profile) || (containerRef.Profile == "") {
  491. // proceed with API Key Auth validation
  492. err := utils.ValidateSecretSelector(store, secretKeyRef)
  493. if err != nil {
  494. return err
  495. }
  496. if secretKeyRef.Name == "" {
  497. return fmt.Errorf("secretAPIKey.name cannot be empty")
  498. }
  499. if secretKeyRef.Key == "" {
  500. return fmt.Errorf("secretAPIKey.key cannot be empty")
  501. }
  502. } else {
  503. // proceed with container auth
  504. if containerRef.TokenLocation == "" {
  505. containerRef.TokenLocation = "/var/run/secrets/tokens/vault-token"
  506. }
  507. if _, err := os.Open(containerRef.TokenLocation); err != nil {
  508. return fmt.Errorf("cannot read container auth token %s. %w", containerRef.TokenLocation, err)
  509. }
  510. }
  511. return nil
  512. }
  513. // Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
  514. func (ibm *providerIBM) Capabilities() esv1beta1.SecretStoreCapabilities {
  515. return esv1beta1.SecretStoreReadOnly
  516. }
  517. func (ibm *providerIBM) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
  518. storeSpec := store.GetSpec()
  519. ibmSpec := storeSpec.Provider.IBM
  520. iStore := &client{
  521. kube: kube,
  522. store: ibmSpec,
  523. namespace: namespace,
  524. storeKind: store.GetObjectKind().GroupVersionKind().Kind,
  525. }
  526. var err error
  527. var secretsManager *sm.SecretsManagerV2
  528. containerAuthProfile := iStore.store.Auth.ContainerAuth.Profile
  529. if containerAuthProfile != "" {
  530. // container-based auth
  531. containerAuthToken := iStore.store.Auth.ContainerAuth.TokenLocation
  532. containerAuthEndpoint := iStore.store.Auth.ContainerAuth.IAMEndpoint
  533. if containerAuthToken == "" {
  534. // API default path
  535. containerAuthToken = "/var/run/secrets/tokens/vault-token"
  536. }
  537. if containerAuthEndpoint == "" {
  538. // API default path
  539. containerAuthEndpoint = "https://iam.cloud.ibm.com"
  540. }
  541. authenticator, err := core.NewContainerAuthenticatorBuilder().
  542. SetIAMProfileName(containerAuthProfile).
  543. SetCRTokenFilename(containerAuthToken).
  544. SetURL(containerAuthEndpoint).
  545. Build()
  546. if err != nil {
  547. return nil, fmt.Errorf(errIBMClient, err)
  548. }
  549. secretsManager, err = sm.NewSecretsManagerV2(&sm.SecretsManagerV2Options{
  550. URL: *storeSpec.Provider.IBM.ServiceURL,
  551. Authenticator: authenticator,
  552. })
  553. if err != nil {
  554. return nil, fmt.Errorf(errIBMClient, err)
  555. }
  556. } else {
  557. // API Key-based auth
  558. if err := iStore.setAuth(ctx); err != nil {
  559. return nil, err
  560. }
  561. secretsManager, err = sm.NewSecretsManagerV2(&sm.SecretsManagerV2Options{
  562. URL: *storeSpec.Provider.IBM.ServiceURL,
  563. Authenticator: &core.IamAuthenticator{
  564. ApiKey: string(iStore.credentials),
  565. },
  566. })
  567. }
  568. // Setup retry options, but only if present
  569. if storeSpec.RetrySettings != nil {
  570. var retryAmount int
  571. var retryDuration time.Duration
  572. if storeSpec.RetrySettings.MaxRetries != nil {
  573. retryAmount = int(*storeSpec.RetrySettings.MaxRetries)
  574. } else {
  575. retryAmount = 3
  576. }
  577. if storeSpec.RetrySettings.RetryInterval != nil {
  578. retryDuration, err = time.ParseDuration(*storeSpec.RetrySettings.RetryInterval)
  579. } else {
  580. retryDuration = 5 * time.Second
  581. }
  582. if err == nil {
  583. secretsManager.Service.EnableRetries(retryAmount, retryDuration)
  584. }
  585. }
  586. if err != nil {
  587. return nil, fmt.Errorf(errIBMClient, err)
  588. }
  589. ibm.IBMClient = secretsManager
  590. ibm.cache = NewCache(defaultCacheSize, defaultCacheExpiry)
  591. return ibm, nil
  592. }
  593. func init() {
  594. esv1beta1.Register(&providerIBM{}, &esv1beta1.SecretStoreProvider{
  595. IBM: &esv1beta1.IBMProvider{},
  596. })
  597. }