provider_test.go 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  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. "reflect"
  18. "strings"
  19. "testing"
  20. "time"
  21. "github.com/IBM/go-sdk-core/v5/core"
  22. sm "github.com/IBM/secrets-manager-go-sdk/v2/secretsmanagerv2"
  23. corev1 "k8s.io/api/core/v1"
  24. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  25. utilpointer "k8s.io/utils/pointer"
  26. clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
  27. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  28. v1 "github.com/external-secrets/external-secrets/apis/meta/v1"
  29. fakesm "github.com/external-secrets/external-secrets/pkg/provider/ibm/fake"
  30. )
  31. const (
  32. errExpectedErr = "wanted error got nil"
  33. secretKey = "test-secret"
  34. secretUUID = "d5deb37a-7883-4fe2-a5e7-3c15420adc76"
  35. )
  36. type secretManagerTestCase struct {
  37. name string
  38. mockClient *fakesm.IBMMockClient
  39. apiInput *sm.GetSecretOptions
  40. apiOutput sm.SecretIntf
  41. listInput *sm.ListSecretsOptions
  42. listOutput *sm.SecretMetadataPaginatedCollection
  43. listError error
  44. ref *esv1beta1.ExternalSecretDataRemoteRef
  45. serviceURL *string
  46. apiErr error
  47. expectError string
  48. expectedSecret string
  49. // for testing secretmap
  50. expectedData map[string][]byte
  51. }
  52. func makeValidSecretManagerTestCase() *secretManagerTestCase {
  53. smtc := secretManagerTestCase{
  54. mockClient: &fakesm.IBMMockClient{},
  55. apiInput: makeValidAPIInput(),
  56. ref: makeValidRef(),
  57. apiOutput: makeValidAPIOutput(),
  58. listInput: makeValidListInput(),
  59. listOutput: makeValidListSecretsOutput(),
  60. listError: nil,
  61. serviceURL: nil,
  62. apiErr: nil,
  63. expectError: "",
  64. expectedSecret: "",
  65. expectedData: map[string][]byte{},
  66. }
  67. mcParams := fakesm.IBMMockClientParams{
  68. GetSecretOptions: smtc.apiInput,
  69. GetSecretOutput: smtc.apiOutput,
  70. GetSecretErr: smtc.apiErr,
  71. ListSecretsOptions: smtc.listInput,
  72. ListSecretsOutput: smtc.listOutput,
  73. ListSecretsErr: smtc.listError,
  74. }
  75. smtc.mockClient.WithValue(mcParams)
  76. return &smtc
  77. }
  78. func makeValidRef() *esv1beta1.ExternalSecretDataRemoteRef {
  79. return &esv1beta1.ExternalSecretDataRemoteRef{
  80. Key: secretUUID,
  81. Version: "default",
  82. }
  83. }
  84. func makeValidAPIInput() *sm.GetSecretOptions {
  85. return &sm.GetSecretOptions{
  86. ID: utilpointer.String(secretUUID),
  87. }
  88. }
  89. func makeValidAPIOutput() sm.SecretIntf {
  90. secret := &sm.Secret{
  91. SecretType: utilpointer.String(sm.Secret_SecretType_Arbitrary),
  92. Name: utilpointer.String("testyname"),
  93. ID: utilpointer.String(secretUUID),
  94. }
  95. var i sm.SecretIntf = secret
  96. return i
  97. }
  98. func makeValidListSecretsOutput() *sm.SecretMetadataPaginatedCollection {
  99. list := sm.SecretMetadataPaginatedCollection{}
  100. return &list
  101. }
  102. func makeValidListInput() *sm.ListSecretsOptions {
  103. listOpt := sm.ListSecretsOptions{}
  104. return &listOpt
  105. }
  106. func makeValidSecretManagerTestCaseCustom(tweaks ...func(smtc *secretManagerTestCase)) *secretManagerTestCase {
  107. smtc := makeValidSecretManagerTestCase()
  108. for _, fn := range tweaks {
  109. fn(smtc)
  110. }
  111. mcParams := fakesm.IBMMockClientParams{
  112. GetSecretOptions: smtc.apiInput,
  113. GetSecretOutput: smtc.apiOutput,
  114. GetSecretErr: smtc.apiErr,
  115. ListSecretsOptions: smtc.listInput,
  116. ListSecretsOutput: smtc.listOutput,
  117. ListSecretsErr: smtc.listError,
  118. }
  119. smtc.mockClient.WithValue(mcParams)
  120. return smtc
  121. }
  122. // This case can be shared by both GetSecret and GetSecretMap tests.
  123. // bad case: set apiErr.
  124. var setAPIErr = func(smtc *secretManagerTestCase) {
  125. smtc.apiErr = fmt.Errorf("oh no")
  126. smtc.expectError = "oh no"
  127. }
  128. var setNilMockClient = func(smtc *secretManagerTestCase) {
  129. smtc.mockClient = nil
  130. smtc.expectError = errUninitalizedIBMProvider
  131. }
  132. // simple tests for Validate Store.
  133. func TestValidateStore(t *testing.T) {
  134. p := providerIBM{}
  135. store := &esv1beta1.SecretStore{
  136. Spec: esv1beta1.SecretStoreSpec{
  137. Provider: &esv1beta1.SecretStoreProvider{
  138. IBM: &esv1beta1.IBMProvider{},
  139. },
  140. },
  141. }
  142. err := p.ValidateStore(store)
  143. if err == nil {
  144. t.Errorf(errExpectedErr)
  145. } else if err.Error() != "serviceURL is required" {
  146. t.Errorf("service URL test failed")
  147. }
  148. url := "my-url"
  149. store.Spec.Provider.IBM.ServiceURL = &url
  150. var nilProfile esv1beta1.IBMAuthContainerAuth
  151. store.Spec.Provider.IBM.Auth.ContainerAuth = nilProfile
  152. err = p.ValidateStore(store)
  153. if err == nil {
  154. t.Errorf(errExpectedErr)
  155. } else if err.Error() != "secretAPIKey.name cannot be empty" {
  156. t.Errorf("KeySelector test failed: expected secret name is required, got %v", err)
  157. }
  158. store.Spec.Provider.IBM.Auth.SecretRef.SecretAPIKey.Name = "foo"
  159. store.Spec.Provider.IBM.Auth.SecretRef.SecretAPIKey.Key = "bar"
  160. ns := "ns-one"
  161. store.Spec.Provider.IBM.Auth.SecretRef.SecretAPIKey.Namespace = &ns
  162. err = p.ValidateStore(store)
  163. if err == nil {
  164. t.Errorf(errExpectedErr)
  165. } else if err.Error() != "namespace not allowed with namespaced SecretStore" {
  166. t.Errorf("KeySelector test failed: expected namespace not allowed, got %v", err)
  167. }
  168. // add container auth test
  169. store.Spec.Provider.IBM = &esv1beta1.IBMProvider{}
  170. store.Spec.Provider.IBM.ServiceURL = &url
  171. store.Spec.Provider.IBM.Auth.ContainerAuth.Profile = "Trusted IAM Profile"
  172. store.Spec.Provider.IBM.Auth.ContainerAuth.TokenLocation = "/a/path/to/nowhere/that/should/exist"
  173. err = p.ValidateStore(store)
  174. expected := "cannot read container auth token"
  175. if !ErrorContains(err, expected) {
  176. t.Errorf("ProfileSelector test failed: %s, expected: '%s'", err.Error(), expected)
  177. }
  178. }
  179. // test the sm<->gcp interface
  180. // make sure correct values are passed and errors are handled accordingly.
  181. func TestIBMSecretManagerGetSecret(t *testing.T) {
  182. secretString := "changedvalue"
  183. secretUsername := "userName"
  184. secretPassword := "P@ssw0rd"
  185. secretAPIKey := "01234567890"
  186. secretCertificate := "certificate_value"
  187. // good case: default version is set
  188. // key is passed in, output is sent back
  189. setSecretString := func(smtc *secretManagerTestCase) {
  190. secret := &sm.ArbitrarySecret{
  191. SecretType: utilpointer.String(sm.Secret_SecretType_Arbitrary),
  192. Name: utilpointer.String("testyname"),
  193. ID: utilpointer.String(secretUUID),
  194. Payload: &secretString,
  195. }
  196. smtc.name = "good case: default version is set"
  197. smtc.apiOutput = secret
  198. smtc.apiInput.ID = utilpointer.String(secretUUID)
  199. smtc.expectedSecret = secretString
  200. }
  201. // good case: custom version set
  202. setCustomKey := func(smtc *secretManagerTestCase) {
  203. secret := &sm.ArbitrarySecret{
  204. SecretType: utilpointer.String(sm.Secret_SecretType_Arbitrary),
  205. Name: utilpointer.String("testyname"),
  206. ID: utilpointer.String(secretUUID),
  207. Payload: &secretString,
  208. }
  209. smtc.name = "good case: custom version set"
  210. smtc.ref.Key = "arbitrary/" + secretUUID
  211. smtc.apiInput.ID = utilpointer.String(secretUUID)
  212. smtc.apiOutput = secret
  213. smtc.expectedSecret = secretString
  214. }
  215. // bad case: username_password type without property
  216. secretUserPass := "username_password/" + secretUUID
  217. badSecretUserPass := func(smtc *secretManagerTestCase) {
  218. secret := &sm.UsernamePasswordSecret{
  219. SecretType: utilpointer.String(sm.Secret_SecretType_UsernamePassword),
  220. Name: utilpointer.String("testyname"),
  221. ID: utilpointer.String(secretUUID),
  222. Username: &secretUsername,
  223. Password: &secretPassword,
  224. }
  225. smtc.name = "bad case: username_password type without property"
  226. smtc.apiInput.ID = utilpointer.String(secretUUID)
  227. smtc.apiOutput = secret
  228. smtc.ref.Key = secretUserPass
  229. smtc.expectError = "remoteRef.property required for secret type username_password"
  230. }
  231. // good case: username_password type with property
  232. funcSetUserPass := func(secretName, property, name string) func(smtc *secretManagerTestCase) {
  233. return func(smtc *secretManagerTestCase) {
  234. secret := &sm.UsernamePasswordSecret{
  235. SecretType: utilpointer.String(sm.Secret_SecretType_UsernamePassword),
  236. Name: utilpointer.String("testyname"),
  237. ID: utilpointer.String(secretUUID),
  238. Username: &secretUsername,
  239. Password: &secretPassword,
  240. }
  241. secretMetadata := &sm.UsernamePasswordSecretMetadata{
  242. Name: utilpointer.String("testyname"),
  243. ID: utilpointer.String(secretUUID),
  244. }
  245. smtc.name = name
  246. smtc.apiInput.ID = utilpointer.String(secretUUID)
  247. smtc.apiOutput = secret
  248. smtc.listInput.Search = utilpointer.String("testyname")
  249. smtc.listOutput.Secrets = make([]sm.SecretMetadataIntf, 1)
  250. smtc.listOutput.Secrets[0] = secretMetadata
  251. smtc.ref.Key = "username_password/" + secretName
  252. smtc.ref.Property = property
  253. if property == "username" {
  254. smtc.expectedSecret = secretUsername
  255. } else {
  256. smtc.expectedSecret = secretPassword
  257. }
  258. }
  259. }
  260. setSecretUserPassByID := funcSetUserPass(secretUUID, "username", "good case: username_password type - get username by ID")
  261. setSecretUserPassUsername := funcSetUserPass("testyname", "username", "good case: username_password type - get username by secret name")
  262. setSecretUserPassPassword := funcSetUserPass("testyname", "password", "good case: username_password type - get password by secret name")
  263. // good case: iam_credentials type
  264. funcSetSecretIam := func(secretName, name string) func(*secretManagerTestCase) {
  265. return func(smtc *secretManagerTestCase) {
  266. secret := &sm.IAMCredentialsSecret{
  267. SecretType: utilpointer.String(sm.Secret_SecretType_IamCredentials),
  268. Name: utilpointer.String("testyname"),
  269. ID: utilpointer.String(secretUUID),
  270. ApiKey: utilpointer.String(secretAPIKey),
  271. }
  272. secretMetadata := &sm.IAMCredentialsSecretMetadata{
  273. Name: utilpointer.String("testyname"),
  274. ID: utilpointer.String(secretUUID),
  275. }
  276. smtc.apiInput.ID = utilpointer.String(secretUUID)
  277. smtc.name = name
  278. smtc.apiOutput = secret
  279. smtc.listInput.Search = utilpointer.String("testyname")
  280. smtc.listOutput.Secrets = make([]sm.SecretMetadataIntf, 1)
  281. smtc.listOutput.Secrets[0] = secretMetadata
  282. smtc.ref.Key = "iam_credentials/" + secretName
  283. smtc.expectedSecret = secretAPIKey
  284. }
  285. }
  286. setSecretIamByID := funcSetSecretIam(secretUUID, "good case: iam_credenatials type - get API Key by ID")
  287. setSecretIamByName := funcSetSecretIam("testyname", "good case: iam_credenatials type - get API Key by name")
  288. funcSetCertSecretTest := func(secret sm.SecretIntf, name, certType string, good bool) func(*secretManagerTestCase) {
  289. return func(smtc *secretManagerTestCase) {
  290. smtc.name = name
  291. smtc.apiInput.ID = utilpointer.String(secretUUID)
  292. smtc.apiOutput = secret
  293. smtc.ref.Key = certType + "/" + secretUUID
  294. if good {
  295. smtc.ref.Property = "certificate"
  296. smtc.expectedSecret = secretCertificate
  297. } else {
  298. smtc.expectError = "remoteRef.property required for secret type " + certType
  299. }
  300. }
  301. }
  302. // good case: imported_cert type with property
  303. importedCert := &sm.ImportedCertificate{
  304. SecretType: utilpointer.String(sm.Secret_SecretType_ImportedCert),
  305. Name: utilpointer.String("testyname"),
  306. ID: utilpointer.String(secretUUID),
  307. Certificate: utilpointer.String(secretCertificate),
  308. Intermediate: utilpointer.String("intermediate"),
  309. PrivateKey: utilpointer.String("private_key"),
  310. }
  311. setSecretCert := funcSetCertSecretTest(importedCert, "good case: imported_cert type with property", sm.Secret_SecretType_ImportedCert, true)
  312. // bad case: imported_cert type without property
  313. badSecretCert := funcSetCertSecretTest(importedCert, "bad case: imported_cert type without property", sm.Secret_SecretType_ImportedCert, false)
  314. // good case: public_cert type with property
  315. publicCert := &sm.PublicCertificate{
  316. SecretType: utilpointer.String(sm.Secret_SecretType_PublicCert),
  317. Name: utilpointer.String("testyname"),
  318. ID: utilpointer.String(secretUUID),
  319. Certificate: utilpointer.String(secretCertificate),
  320. Intermediate: utilpointer.String("intermediate"),
  321. PrivateKey: utilpointer.String("private_key"),
  322. }
  323. setSecretPublicCert := funcSetCertSecretTest(publicCert, "good case: public_cert type with property", sm.Secret_SecretType_PublicCert, true)
  324. // bad case: public_cert type without property
  325. badSecretPublicCert := funcSetCertSecretTest(publicCert, "bad case: public_cert type without property", sm.Secret_SecretType_PublicCert, false)
  326. // good case: private_cert type with property
  327. privateCert := &sm.PrivateCertificate{
  328. SecretType: utilpointer.String(sm.Secret_SecretType_PublicCert),
  329. Name: utilpointer.String("testyname"),
  330. ID: utilpointer.String(secretUUID),
  331. Certificate: utilpointer.String(secretCertificate),
  332. PrivateKey: utilpointer.String("private_key"),
  333. }
  334. setSecretPrivateCert := funcSetCertSecretTest(privateCert, "good case: private_cert type with property", sm.Secret_SecretType_PrivateCert, true)
  335. // bad case: private_cert type without property
  336. badSecretPrivateCert := funcSetCertSecretTest(privateCert, "bad case: private_cert type without property", sm.Secret_SecretType_PrivateCert, false)
  337. secretDataKV := make(map[string]interface{})
  338. secretDataKV["key1"] = "val1"
  339. secretDataKVComplex := make(map[string]interface{})
  340. secretKVComplex := `{"key1":"val1","key2":"val2","key3":"val3","keyC":{"keyC1":"valC1","keyC2":"valC2"},"special.log":"file-content"}`
  341. json.Unmarshal([]byte(secretKVComplex), &secretDataKVComplex)
  342. secretKV := "kv/" + secretUUID
  343. // bad case: kv type with key which is not in payload
  344. badSecretKV := func(smtc *secretManagerTestCase) {
  345. secret := &sm.KVSecret{
  346. SecretType: utilpointer.String(sm.Secret_SecretType_Kv),
  347. Name: utilpointer.String("testyname"),
  348. ID: utilpointer.String(secretUUID),
  349. Data: secretDataKV,
  350. }
  351. smtc.name = "bad case: kv type with key which is not in payload"
  352. smtc.apiInput.ID = utilpointer.String(secretUUID)
  353. smtc.apiOutput = secret
  354. smtc.ref.Key = secretKV
  355. smtc.ref.Property = "other-key"
  356. smtc.expectError = "key other-key does not exist in secret kv/" + secretUUID
  357. }
  358. // good case: kv type with property
  359. setSecretKV := func(smtc *secretManagerTestCase) {
  360. secret := &sm.KVSecret{
  361. SecretType: utilpointer.String(sm.Secret_SecretType_Kv),
  362. Name: utilpointer.String("testyname"),
  363. ID: utilpointer.String(secretUUID),
  364. Data: secretDataKV,
  365. }
  366. smtc.name = "good case: kv type with property"
  367. smtc.apiInput.ID = utilpointer.String(secretUUID)
  368. smtc.apiOutput = secret
  369. smtc.ref.Key = secretKV
  370. smtc.ref.Property = "key1"
  371. smtc.expectedSecret = "val1"
  372. }
  373. // good case: kv type with property, returns specific value
  374. setSecretKVWithKey := func(smtc *secretManagerTestCase) {
  375. secret := &sm.KVSecret{
  376. SecretType: utilpointer.String(sm.Secret_SecretType_Kv),
  377. Name: utilpointer.String("testyname"),
  378. ID: utilpointer.String(secretUUID),
  379. Data: secretDataKVComplex,
  380. }
  381. smtc.name = "good case: kv type with property, returns specific value"
  382. smtc.apiInput.ID = utilpointer.String(secretUUID)
  383. smtc.apiOutput = secret
  384. smtc.ref.Key = secretKV
  385. smtc.ref.Property = "key2"
  386. smtc.expectedSecret = "val2"
  387. }
  388. // good case: kv type with property and path, returns specific value
  389. setSecretKVWithKeyPath := func(smtc *secretManagerTestCase) {
  390. secret := &sm.KVSecret{
  391. SecretType: utilpointer.String(sm.Secret_SecretType_Kv),
  392. Name: utilpointer.String("testyname"),
  393. ID: utilpointer.String(secretUUID),
  394. Data: secretDataKVComplex,
  395. }
  396. smtc.name = "good case: kv type with property and path, returns specific value"
  397. smtc.apiInput.ID = utilpointer.String(secretUUID)
  398. smtc.apiOutput = secret
  399. smtc.ref.Key = secretKV
  400. smtc.ref.Property = "keyC.keyC2"
  401. smtc.expectedSecret = "valC2"
  402. }
  403. // good case: kv type with property and dot, returns specific value
  404. setSecretKVWithKeyDot := func(smtc *secretManagerTestCase) {
  405. secret := &sm.KVSecret{
  406. SecretType: utilpointer.String(sm.Secret_SecretType_Kv),
  407. Name: utilpointer.String("testyname"),
  408. ID: utilpointer.String(secretUUID),
  409. Data: secretDataKVComplex,
  410. }
  411. smtc.name = "good case: kv type with property and dot, returns specific value"
  412. smtc.apiInput.ID = utilpointer.String(secretUUID)
  413. smtc.apiOutput = secret
  414. smtc.ref.Key = secretKV
  415. smtc.ref.Property = "special.log"
  416. smtc.expectedSecret = "file-content"
  417. }
  418. // good case: kv type without property, returns all
  419. setSecretKVWithOutKey := func(smtc *secretManagerTestCase) {
  420. secret := &sm.KVSecret{
  421. SecretType: utilpointer.String(sm.Secret_SecretType_Kv),
  422. Name: utilpointer.String("testyname"),
  423. ID: utilpointer.String(secretUUID),
  424. Data: secretDataKVComplex,
  425. }
  426. smtc.name = "good case: kv type without property, returns all"
  427. smtc.apiInput.ID = utilpointer.String(secretUUID)
  428. smtc.apiOutput = secret
  429. smtc.ref.Key = secretKV
  430. smtc.expectedSecret = secretKVComplex
  431. }
  432. successCases := []*secretManagerTestCase{
  433. makeValidSecretManagerTestCaseCustom(setSecretString),
  434. makeValidSecretManagerTestCaseCustom(setCustomKey),
  435. makeValidSecretManagerTestCaseCustom(setAPIErr),
  436. makeValidSecretManagerTestCaseCustom(setNilMockClient),
  437. makeValidSecretManagerTestCaseCustom(badSecretUserPass),
  438. makeValidSecretManagerTestCaseCustom(setSecretUserPassByID),
  439. makeValidSecretManagerTestCaseCustom(setSecretUserPassUsername),
  440. makeValidSecretManagerTestCaseCustom(setSecretUserPassPassword),
  441. makeValidSecretManagerTestCaseCustom(setSecretIamByID),
  442. makeValidSecretManagerTestCaseCustom(setSecretIamByName),
  443. makeValidSecretManagerTestCaseCustom(setSecretCert),
  444. makeValidSecretManagerTestCaseCustom(setSecretKV),
  445. makeValidSecretManagerTestCaseCustom(setSecretKVWithKey),
  446. makeValidSecretManagerTestCaseCustom(setSecretKVWithKeyPath),
  447. makeValidSecretManagerTestCaseCustom(setSecretKVWithKeyDot),
  448. makeValidSecretManagerTestCaseCustom(setSecretKVWithOutKey),
  449. makeValidSecretManagerTestCaseCustom(badSecretKV),
  450. makeValidSecretManagerTestCaseCustom(badSecretCert),
  451. makeValidSecretManagerTestCaseCustom(setSecretPublicCert),
  452. makeValidSecretManagerTestCaseCustom(badSecretPublicCert),
  453. makeValidSecretManagerTestCaseCustom(setSecretPrivateCert),
  454. makeValidSecretManagerTestCaseCustom(badSecretPrivateCert),
  455. }
  456. sm := providerIBM{}
  457. for k, v := range successCases {
  458. t.Run(v.name, func(t *testing.T) {
  459. sm.IBMClient = v.mockClient
  460. sm.cache = NewCache(10, 1*time.Minute)
  461. out, err := sm.GetSecret(context.Background(), *v.ref)
  462. if !ErrorContains(err, v.expectError) {
  463. t.Errorf("[%d] unexpected error: %s, expected: '%s'", k, err.Error(), v.expectError)
  464. }
  465. if string(out) != v.expectedSecret {
  466. t.Errorf("[%d] unexpected secret: expected %s, got %s", k, v.expectedSecret, string(out))
  467. }
  468. })
  469. }
  470. }
  471. func TestGetSecretMap(t *testing.T) {
  472. secretUsername := "user1"
  473. secretPassword := "P@ssw0rd"
  474. secretAPIKey := "01234567890"
  475. secretCertificate := "certificate_value"
  476. secretPrivateKey := "private_key_value"
  477. secretIntermediate := "intermediate_value"
  478. secretComplex := map[string]interface{}{
  479. "key1": "val1",
  480. "key2": "val2",
  481. "keyC": map[string]interface{}{
  482. "keyC1": map[string]string{
  483. "keyA": "valA",
  484. "keyB": "valB",
  485. },
  486. },
  487. }
  488. // good case: arbitrary
  489. setArbitrary := func(smtc *secretManagerTestCase) {
  490. payload := `{"foo":"bar"}`
  491. secret := &sm.ArbitrarySecret{
  492. Name: utilpointer.String("testyname"),
  493. ID: utilpointer.String(secretUUID),
  494. SecretType: utilpointer.String(sm.Secret_SecretType_Arbitrary),
  495. Payload: &payload,
  496. }
  497. smtc.name = "good case: arbitrary"
  498. smtc.apiInput.ID = utilpointer.String(secretUUID)
  499. smtc.apiOutput = secret
  500. smtc.ref.Key = secretUUID
  501. smtc.expectedData["arbitrary"] = []byte(payload)
  502. }
  503. // good case: username_password
  504. setSecretUserPass := func(smtc *secretManagerTestCase) {
  505. secret := &sm.UsernamePasswordSecret{
  506. Name: utilpointer.String("testyname"),
  507. ID: utilpointer.String(secretUUID),
  508. SecretType: utilpointer.String(sm.Secret_SecretType_UsernamePassword),
  509. Username: &secretUsername,
  510. Password: &secretPassword,
  511. }
  512. smtc.name = "good case: username_password"
  513. smtc.apiInput.ID = utilpointer.String(secretUUID)
  514. smtc.apiOutput = secret
  515. smtc.ref.Key = "username_password/" + secretUUID
  516. smtc.expectedData["username"] = []byte(secretUsername)
  517. smtc.expectedData["password"] = []byte(secretPassword)
  518. }
  519. // good case: iam_credentials
  520. setSecretIam := func(smtc *secretManagerTestCase) {
  521. secret := &sm.IAMCredentialsSecret{
  522. Name: utilpointer.String("testyname"),
  523. ID: utilpointer.String(secretUUID),
  524. SecretType: utilpointer.String(sm.Secret_SecretType_IamCredentials),
  525. ApiKey: utilpointer.String(secretAPIKey),
  526. }
  527. smtc.name = "good case: iam_credentials"
  528. smtc.apiInput.ID = utilpointer.String(secretUUID)
  529. smtc.apiOutput = secret
  530. smtc.ref.Key = "iam_credentials/" + secretUUID
  531. smtc.expectedData["apikey"] = []byte(secretAPIKey)
  532. }
  533. funcCertTest := func(secret sm.SecretIntf, name, certType string) func(*secretManagerTestCase) {
  534. return func(smtc *secretManagerTestCase) {
  535. smtc.name = name
  536. smtc.apiInput.ID = utilpointer.String(secretUUID)
  537. smtc.apiOutput = secret
  538. smtc.ref.Key = certType + "/" + secretUUID
  539. smtc.expectedData["certificate"] = []byte(secretCertificate)
  540. smtc.expectedData["private_key"] = []byte(secretPrivateKey)
  541. smtc.expectedData["intermediate"] = []byte(secretIntermediate)
  542. }
  543. }
  544. // good case: imported_cert
  545. importedCert := &sm.ImportedCertificate{
  546. SecretType: utilpointer.String(sm.Secret_SecretType_ImportedCert),
  547. Name: utilpointer.String("testyname"),
  548. ID: utilpointer.String(secretUUID),
  549. Certificate: utilpointer.String(secretCertificate),
  550. Intermediate: utilpointer.String(secretIntermediate),
  551. PrivateKey: utilpointer.String(secretPrivateKey),
  552. }
  553. setSecretCert := funcCertTest(importedCert, "good case: imported_cert", sm.Secret_SecretType_ImportedCert)
  554. // good case: public_cert
  555. publicCert := &sm.PublicCertificate{
  556. SecretType: utilpointer.String(sm.Secret_SecretType_PublicCert),
  557. Name: utilpointer.String("testyname"),
  558. ID: utilpointer.String(secretUUID),
  559. Certificate: utilpointer.String(secretCertificate),
  560. Intermediate: utilpointer.String(secretIntermediate),
  561. PrivateKey: utilpointer.String(secretPrivateKey),
  562. }
  563. setSecretPublicCert := funcCertTest(publicCert, "good case: public_cert", sm.Secret_SecretType_PublicCert)
  564. // good case: private_cert
  565. setSecretPrivateCert := func(smtc *secretManagerTestCase) {
  566. secret := &sm.PrivateCertificate{
  567. Name: utilpointer.String("testyname"),
  568. ID: utilpointer.String(secretUUID),
  569. SecretType: utilpointer.String(sm.Secret_SecretType_PrivateCert),
  570. Certificate: &secretCertificate,
  571. PrivateKey: &secretPrivateKey,
  572. }
  573. smtc.name = "good case: private_cert"
  574. smtc.apiInput.ID = utilpointer.String(secretUUID)
  575. smtc.apiOutput = secret
  576. smtc.ref.Key = "private_cert/" + secretUUID
  577. smtc.expectedData["certificate"] = []byte(secretCertificate)
  578. smtc.expectedData["private_key"] = []byte(secretPrivateKey)
  579. }
  580. secretKeyKV := "kv/" + secretUUID
  581. // good case: kv, no property, return entire payload as key:value pairs
  582. setSecretKV := func(smtc *secretManagerTestCase) {
  583. secret := &sm.KVSecret{
  584. Name: utilpointer.String("testyname"),
  585. ID: utilpointer.String(secretUUID),
  586. SecretType: utilpointer.String(sm.Secret_SecretType_Kv),
  587. Data: secretComplex,
  588. }
  589. smtc.name = "good case: kv, no property, return entire payload as key:value pairs"
  590. smtc.apiInput.ID = core.StringPtr(secretUUID)
  591. smtc.apiOutput = secret
  592. smtc.ref.Key = secretKeyKV
  593. smtc.expectedData["key1"] = []byte("val1")
  594. smtc.expectedData["key2"] = []byte("val2")
  595. smtc.expectedData["keyC"] = []byte(`{"keyC1":{"keyA":"valA","keyB":"valB"}}`)
  596. }
  597. // good case: kv, with property
  598. setSecretKVWithProperty := func(smtc *secretManagerTestCase) {
  599. secret := &sm.KVSecret{
  600. Name: utilpointer.String("d5deb37a-7883-4fe2-a5e7-3c15420adc76"),
  601. ID: utilpointer.String(secretUUID),
  602. SecretType: utilpointer.String(sm.Secret_SecretType_Kv),
  603. Data: secretComplex,
  604. }
  605. smtc.name = "good case: kv, with property"
  606. smtc.apiInput.ID = core.StringPtr(secretUUID)
  607. smtc.ref.Property = "keyC"
  608. smtc.apiOutput = secret
  609. smtc.ref.Key = secretKeyKV
  610. smtc.expectedData["keyC1"] = []byte(`{"keyA":"valA","keyB":"valB"}`)
  611. }
  612. // good case: kv, with property and path
  613. setSecretKVWithPathAndProperty := func(smtc *secretManagerTestCase) {
  614. secret := &sm.KVSecret{
  615. Name: utilpointer.String(secretUUID),
  616. ID: utilpointer.String(secretUUID),
  617. SecretType: utilpointer.String(sm.Secret_SecretType_Kv),
  618. Data: secretComplex,
  619. }
  620. smtc.name = "good case: kv, with property and path"
  621. smtc.apiInput.ID = core.StringPtr(secretUUID)
  622. smtc.ref.Property = "keyC.keyC1"
  623. smtc.apiOutput = secret
  624. smtc.ref.Key = secretKeyKV
  625. smtc.expectedData["keyA"] = []byte("valA")
  626. smtc.expectedData["keyB"] = []byte("valB")
  627. }
  628. // bad case: kv, with property and path
  629. badSecretKVWithUnknownProperty := func(smtc *secretManagerTestCase) {
  630. secret := &sm.KVSecret{
  631. Name: utilpointer.String("testyname"),
  632. ID: utilpointer.String(secretUUID),
  633. SecretType: utilpointer.String(sm.Secret_SecretType_Kv),
  634. Data: secretComplex,
  635. }
  636. smtc.name = "bad case: kv, with property and path"
  637. smtc.apiInput.ID = core.StringPtr(secretUUID)
  638. smtc.ref.Property = "unknown.property"
  639. smtc.apiOutput = secret
  640. smtc.ref.Key = secretKeyKV
  641. smtc.expectError = "key unknown.property does not exist in secret " + secretKeyKV
  642. }
  643. successCases := []*secretManagerTestCase{
  644. makeValidSecretManagerTestCaseCustom(setArbitrary),
  645. makeValidSecretManagerTestCaseCustom(setNilMockClient),
  646. makeValidSecretManagerTestCaseCustom(setAPIErr),
  647. makeValidSecretManagerTestCaseCustom(setSecretUserPass),
  648. makeValidSecretManagerTestCaseCustom(setSecretIam),
  649. makeValidSecretManagerTestCaseCustom(setSecretCert),
  650. makeValidSecretManagerTestCaseCustom(setSecretKV),
  651. makeValidSecretManagerTestCaseCustom(setSecretKVWithProperty),
  652. makeValidSecretManagerTestCaseCustom(setSecretKVWithPathAndProperty),
  653. makeValidSecretManagerTestCaseCustom(badSecretKVWithUnknownProperty),
  654. makeValidSecretManagerTestCaseCustom(setSecretPublicCert),
  655. makeValidSecretManagerTestCaseCustom(setSecretPrivateCert),
  656. }
  657. sm := providerIBM{}
  658. for k, v := range successCases {
  659. t.Run(v.name, func(t *testing.T) {
  660. sm.IBMClient = v.mockClient
  661. out, err := sm.GetSecretMap(context.Background(), *v.ref)
  662. if !ErrorContains(err, v.expectError) {
  663. t.Errorf(" unexpected error: %s, expected: '%s'", err.Error(), v.expectError)
  664. }
  665. if err == nil && !reflect.DeepEqual(out, v.expectedData) {
  666. t.Errorf("[%d] unexpected secret data: expected %+v, got %v", k, v.expectedData, out)
  667. }
  668. })
  669. }
  670. }
  671. func TestValidRetryInput(t *testing.T) {
  672. sm := providerIBM{}
  673. invalid := "Invalid"
  674. serviceURL := "http://fake-service-url.cool"
  675. spec := &esv1beta1.SecretStore{
  676. Spec: esv1beta1.SecretStoreSpec{
  677. Provider: &esv1beta1.SecretStoreProvider{
  678. IBM: &esv1beta1.IBMProvider{
  679. Auth: esv1beta1.IBMAuth{
  680. SecretRef: esv1beta1.IBMAuthSecretRef{
  681. SecretAPIKey: v1.SecretKeySelector{
  682. Name: "fake-secret",
  683. Key: "fake-key",
  684. },
  685. },
  686. },
  687. ServiceURL: &serviceURL,
  688. },
  689. },
  690. RetrySettings: &esv1beta1.SecretStoreRetrySettings{
  691. RetryInterval: &invalid,
  692. },
  693. },
  694. }
  695. expected := fmt.Sprintf("cannot setup new ibm client: time: invalid duration %q", invalid)
  696. ctx := context.TODO()
  697. kube := clientfake.NewClientBuilder().WithObjects(&corev1.Secret{
  698. ObjectMeta: metav1.ObjectMeta{
  699. Name: "fake-secret",
  700. Namespace: "default",
  701. },
  702. Data: map[string][]byte{
  703. "fake-key": []byte("ImAFakeApiKey"),
  704. },
  705. }).Build()
  706. _, err := sm.NewClient(ctx, spec, kube, "default")
  707. if !ErrorContains(err, expected) {
  708. t.Errorf("CheckValidRetryInput unexpected error: %s, expected: '%s'", err.Error(), expected)
  709. }
  710. }
  711. func ErrorContains(out error, want string) bool {
  712. if out == nil {
  713. return want == ""
  714. }
  715. if want == "" {
  716. return false
  717. }
  718. return strings.Contains(out.Error(), want)
  719. }