provider_test.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  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 vault
  13. import (
  14. "context"
  15. "errors"
  16. "fmt"
  17. "testing"
  18. "github.com/google/go-cmp/cmp"
  19. vault "github.com/hashicorp/vault/api"
  20. corev1 "k8s.io/api/core/v1"
  21. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  22. typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
  23. "k8s.io/utils/ptr"
  24. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  25. clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
  26. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  27. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  28. utilfake "github.com/external-secrets/external-secrets/pkg/provider/util/fake"
  29. "github.com/external-secrets/external-secrets/pkg/provider/vault/fake"
  30. "github.com/external-secrets/external-secrets/pkg/provider/vault/util"
  31. )
  32. const (
  33. tokenSecretName = "example-secret-token"
  34. secretDataString = "some-creds"
  35. tlsAuthCerts = "tls-auth-certs"
  36. tlsKey = "tls.key"
  37. tlsCrt = "tls.crt"
  38. vaultCert = "vault-cert"
  39. )
  40. var (
  41. secretStorePath = "secret"
  42. )
  43. func makeValidSecretStoreWithVersion(v esv1beta1.VaultKVStoreVersion) *esv1beta1.SecretStore {
  44. return &esv1beta1.SecretStore{
  45. ObjectMeta: metav1.ObjectMeta{
  46. Name: "vault-store",
  47. Namespace: "default",
  48. },
  49. Spec: esv1beta1.SecretStoreSpec{
  50. Provider: &esv1beta1.SecretStoreProvider{
  51. Vault: &esv1beta1.VaultProvider{
  52. Server: "vault.example.com",
  53. Path: &secretStorePath,
  54. Version: v,
  55. Auth: esv1beta1.VaultAuth{
  56. Kubernetes: &esv1beta1.VaultKubernetesAuth{
  57. Path: "kubernetes",
  58. Role: "kubernetes-auth-role",
  59. ServiceAccountRef: &esmeta.ServiceAccountSelector{
  60. Name: "example-sa",
  61. },
  62. },
  63. },
  64. },
  65. },
  66. },
  67. }
  68. }
  69. func makeValidSecretStore() *esv1beta1.SecretStore {
  70. return makeValidSecretStoreWithVersion(esv1beta1.VaultKVStoreV2)
  71. }
  72. func makeValidSecretStoreWithCerts() *esv1beta1.SecretStore {
  73. return &esv1beta1.SecretStore{
  74. ObjectMeta: metav1.ObjectMeta{
  75. Name: "vault-store",
  76. Namespace: "default",
  77. },
  78. Spec: esv1beta1.SecretStoreSpec{
  79. Provider: &esv1beta1.SecretStoreProvider{
  80. Vault: &esv1beta1.VaultProvider{
  81. Server: "vault.example.com",
  82. Path: &secretStorePath,
  83. Version: esv1beta1.VaultKVStoreV2,
  84. Auth: esv1beta1.VaultAuth{
  85. Cert: &esv1beta1.VaultCertAuth{
  86. ClientCert: esmeta.SecretKeySelector{
  87. Name: tlsAuthCerts,
  88. Key: tlsCrt,
  89. },
  90. SecretRef: esmeta.SecretKeySelector{
  91. Name: tlsAuthCerts,
  92. Key: tlsKey,
  93. },
  94. },
  95. },
  96. },
  97. },
  98. },
  99. }
  100. }
  101. func makeValidSecretStoreWithK8sCerts(isSecret bool) *esv1beta1.SecretStore {
  102. store := makeSecretStore()
  103. caProvider := &esv1beta1.CAProvider{
  104. Name: vaultCert,
  105. Key: "cert",
  106. }
  107. if isSecret {
  108. caProvider.Type = "Secret"
  109. } else {
  110. caProvider.Type = "ConfigMap"
  111. }
  112. store.Spec.Provider.Vault.CAProvider = caProvider
  113. return store
  114. }
  115. func makeInvalidClusterSecretStoreWithK8sCerts() *esv1beta1.ClusterSecretStore {
  116. return &esv1beta1.ClusterSecretStore{
  117. TypeMeta: metav1.TypeMeta{
  118. Kind: "ClusterSecretStore",
  119. },
  120. ObjectMeta: metav1.ObjectMeta{
  121. Name: "vault-store",
  122. Namespace: "default",
  123. },
  124. Spec: esv1beta1.SecretStoreSpec{
  125. Provider: &esv1beta1.SecretStoreProvider{
  126. Vault: &esv1beta1.VaultProvider{
  127. Server: "vault.example.com",
  128. Path: &secretStorePath,
  129. Version: "v2",
  130. Auth: esv1beta1.VaultAuth{
  131. Kubernetes: &esv1beta1.VaultKubernetesAuth{
  132. Path: "kubernetes",
  133. Role: "kubernetes-auth-role",
  134. ServiceAccountRef: &esmeta.ServiceAccountSelector{
  135. Name: "example-sa",
  136. },
  137. },
  138. },
  139. CAProvider: &esv1beta1.CAProvider{
  140. Name: vaultCert,
  141. Key: "cert",
  142. Type: "Secret",
  143. },
  144. },
  145. },
  146. },
  147. }
  148. }
  149. func makeValidSecretStoreWithIamAuthSecret() *esv1beta1.SecretStore {
  150. return &esv1beta1.SecretStore{
  151. ObjectMeta: metav1.ObjectMeta{
  152. Name: "vault-store",
  153. Namespace: "default",
  154. },
  155. Spec: esv1beta1.SecretStoreSpec{
  156. Provider: &esv1beta1.SecretStoreProvider{
  157. Vault: &esv1beta1.VaultProvider{
  158. Server: "https://vault.example.com:8200",
  159. Path: &secretStorePath,
  160. Version: esv1beta1.VaultKVStoreV2,
  161. Auth: esv1beta1.VaultAuth{
  162. Iam: &esv1beta1.VaultIamAuth{
  163. Path: "aws",
  164. Region: "us-east-1",
  165. Role: "vault-role",
  166. SecretRef: &esv1beta1.VaultAwsAuthSecretRef{
  167. AccessKeyID: esmeta.SecretKeySelector{
  168. Name: "vault-iam-creds-secret",
  169. Key: "access-key",
  170. },
  171. SecretAccessKey: esmeta.SecretKeySelector{
  172. Name: "vault-iam-creds-secret",
  173. Key: "secret-access-key",
  174. },
  175. SessionToken: &esmeta.SecretKeySelector{
  176. Name: "vault-iam-creds-secret",
  177. Key: "secret-session-token",
  178. },
  179. },
  180. },
  181. },
  182. },
  183. },
  184. },
  185. }
  186. }
  187. type secretStoreTweakFn func(s *esv1beta1.SecretStore)
  188. func makeSecretStore(tweaks ...secretStoreTweakFn) *esv1beta1.SecretStore {
  189. store := makeValidSecretStore()
  190. for _, fn := range tweaks {
  191. fn(store)
  192. }
  193. return store
  194. }
  195. func makeClusterSecretStore(tweaks ...secretStoreTweakFn) *esv1beta1.ClusterSecretStore {
  196. store := makeValidSecretStore()
  197. for _, fn := range tweaks {
  198. fn(store)
  199. }
  200. return &esv1beta1.ClusterSecretStore{
  201. TypeMeta: metav1.TypeMeta{
  202. Kind: esv1beta1.ClusterSecretStoreKind,
  203. },
  204. ObjectMeta: store.ObjectMeta,
  205. Spec: store.Spec,
  206. }
  207. }
  208. type args struct {
  209. newClientFunc func(c *vault.Config) (util.Client, error)
  210. store esv1beta1.GenericStore
  211. kube kclient.Client
  212. corev1 typedcorev1.CoreV1Interface
  213. ns string
  214. }
  215. type want struct {
  216. err error
  217. }
  218. type testCase struct {
  219. reason string
  220. args args
  221. want want
  222. }
  223. func TestNewVault(t *testing.T) {
  224. errBoom := errors.New("boom")
  225. secretClientKey := []byte(`-----BEGIN PRIVATE KEY-----
  226. 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
  227. -----END PRIVATE KEY-----`)
  228. clientCrt := []byte(`-----BEGIN CERTIFICATE-----
  229. MIIFkTCCA3mgAwIBAgIUBEUg3m/WqAsWHG4Q/II3IePFfuowDQYJKoZIhvcNAQELBQAwWDELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDERMA8GA1UEAwwIdmF1bHQtY2EwHhcNMjIwNzI5MjEyMjE4WhcNMzkwMTAxMjEyMjE4WjBYMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMREwDwYDVQQDDAh2YXVsdC1jYTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKLhwbYLEd6M5dpZbReuLg9tbK5qKe6sJm5Qs8sLSMmwkXTOSrvvw7smV5bOHtCGpUEooiFbos1RVL22YYd8cLu59oev1i1p3NWSIPNAq0DQKBxyj3wJ9ftvOfmlmf/J+dtE39pPLFPnffkMWEdzT8UImfZD/kf1S1fotHcffNtP0ijfZPQHo4BQooH/e7PEAQIXDBIrxSoZR57wkoYGtTXRdEAwbE5zUE5ZikIdZlEfYVEYiBL5vBgc5dSM+/oUfurH7AIzOXGp30sa+JzYKkUTQGISw4siJj+oSqjO93Zo4tWEE+NP/0tNe9FnBf+oDuHhgiyerk3yU3jK2vJvXc3191FWDKZXKQaRoCaHnMDgMiDjxQtbM590/BFDWRWrZNGaPciVwmw2foyAclNtGq8J0kzIDn0VRkL35Ad8LfTuxXZpY+hVPC5TIPek4W7grQtX44ohVDw5M6oClucv104tXHjAVVgTfaVMLi1F3FRTwwqI8ShPX0D5ssw+tkeepcIhHMvDB97AgKBM1g24MdX3c6aokrghdwXxQbTS/6lHD66apc3E2STTHeCt9fnDSwEZlvK6iNgedBDHrBl9SXeYTMnbOWYIHX/YYq1efq0gOZHHN4nZuBopOMb+4K/04a2nVUuafdv/eoL6F7h+/+UaH/N3+LkkxWAxcz0w9GVZAgMBAAGjUzBRMB0GA1UdDgQWBBQuIVwmjMZvkq+jf6ViTelH5KDBVDAfBgNVHSMEGDAWgBQuIVwmjMZvkq+jf6ViTelH5KDBVDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQAk4kNyFzmiKnREmi5PPj7xGAtv2aJIdMEfcZJ9e+H0Nb2aCvMvZsDodduXu6G5+1opd45v0AeTjLBkXDO6/8vnyM32VZEEKCAwMCLcOLD1z0+r+gaurDYMOGU5qr8hQadHKFsxEDYnR/9KdHhBg6A8qE2cOQa1ryu34DnWQ3m0CBApClf1YBRp/4T8BmHumfH6odD96H30HVzINrd9WM2hR9GRE3xqQyfwlvqmGn9S6snSVa+mcJ6w2wNE2LPGx0kOtBeOIUdfSsEgvSRjbowSHz9lohFZ0LxJYyizCA5vnMmYyhhkfJqm7YtjHkGWgXmqpH9BFt0D3gfORlIh787nuWfxtZ+554rDyQmPjYQG/qF4+Awehr4RxiGWTox1C67G/RzA6TOXX09xuFY+3U1ich90/KffvhoHvRVfhzxx+HUUY2qSU3HqQDzgieQQBaMuOhd1i6pua+/kPSXkuXqnIs8daao/goR5iU/lPLs7M8Dy7xZ9adzbIPuNuzHir2UuvtPlW+x/sSvOnVL9r/7TrAuWhdScglQ70EInPDVX7BgDWKrZUh86N4d7fu2f/T+6VoUSGEjq8obCj3BQ61mNEoftKVECUO4MMUdat6pY/4Xh6Dwc+FnbvR2+sX7IzI7FtgOrfO6abT+LCAR0R+UXyvnqZcjK2zkHz4DfXFbCQg==
  230. -----END CERTIFICATE-----`)
  231. secretData := []byte(secretDataString)
  232. cases := map[string]testCase{
  233. "InvalidVaultStore": {
  234. reason: "Should return error if given an invalid vault store.",
  235. args: args{
  236. store: &esv1beta1.SecretStore{},
  237. },
  238. want: want{
  239. err: errors.New(errVaultStore),
  240. },
  241. },
  242. "InvalidRetrySettings": {
  243. reason: "Should return error if given an invalid Retry Interval.",
  244. args: args{
  245. store: makeSecretStore(func(s *esv1beta1.SecretStore) {
  246. s.Spec.RetrySettings = &esv1beta1.SecretStoreRetrySettings{
  247. MaxRetries: ptr.To(int32(3)),
  248. RetryInterval: ptr.To("not-an-interval"),
  249. }
  250. }),
  251. },
  252. want: want{
  253. err: errors.New("time: invalid duration \"not-an-interval\""),
  254. },
  255. },
  256. "ValidRetrySettings": {
  257. reason: "Should return a Vault provider with custom retry settings",
  258. args: args{
  259. store: makeSecretStore(func(s *esv1beta1.SecretStore) {
  260. s.Spec.RetrySettings = &esv1beta1.SecretStoreRetrySettings{
  261. MaxRetries: ptr.To(int32(3)),
  262. RetryInterval: ptr.To("10m"),
  263. }
  264. }),
  265. ns: "default",
  266. kube: clientfake.NewClientBuilder().Build(),
  267. corev1: utilfake.NewCreateTokenMock().WithToken("ok"),
  268. newClientFunc: fake.ClientWithLoginMock,
  269. },
  270. want: want{
  271. err: nil,
  272. },
  273. },
  274. "AddVaultStoreCertsError": {
  275. reason: "Should return error if given an invalid CA certificate.",
  276. args: args{
  277. store: makeSecretStore(func(s *esv1beta1.SecretStore) {
  278. s.Spec.Provider.Vault.CABundle = []byte("badcertdata")
  279. }),
  280. },
  281. want: want{
  282. err: fmt.Errorf(errVaultCert, errors.New("failed to parse certificates from CertPool")),
  283. },
  284. },
  285. "VaultAuthFormatError": {
  286. reason: "Should return error if no valid authentication method is given.",
  287. args: args{
  288. store: makeSecretStore(func(s *esv1beta1.SecretStore) {
  289. s.Spec.Provider.Vault.Auth = esv1beta1.VaultAuth{}
  290. }),
  291. },
  292. want: want{
  293. err: errors.New(errAuthFormat),
  294. },
  295. },
  296. "GetKubeServiceAccountError": {
  297. reason: "Should return error if fetching kubernetes secret fails.",
  298. args: args{
  299. newClientFunc: fake.ClientWithLoginMock,
  300. ns: "default",
  301. kube: clientfake.NewClientBuilder().Build(),
  302. store: makeSecretStore(),
  303. corev1: utilfake.NewCreateTokenMock().WithError(errBoom),
  304. },
  305. want: want{
  306. err: fmt.Errorf(errGetKubeSATokenRequest, "example-sa", errBoom),
  307. },
  308. },
  309. "GetKubeSecretError": {
  310. reason: "Should return error if fetching kubernetes secret fails.",
  311. args: args{
  312. ns: "default",
  313. store: makeSecretStore(func(s *esv1beta1.SecretStore) {
  314. s.Spec.Provider.Vault.Auth.Kubernetes.ServiceAccountRef = nil
  315. s.Spec.Provider.Vault.Auth.Kubernetes.SecretRef = &esmeta.SecretKeySelector{
  316. Name: "vault-secret",
  317. Key: "key",
  318. }
  319. }),
  320. kube: clientfake.NewClientBuilder().Build(),
  321. },
  322. want: want{
  323. err: fmt.Errorf(`cannot get Kubernetes secret "vault-secret": %w`, errors.New(`secrets "vault-secret" not found`)),
  324. },
  325. },
  326. "SuccessfulVaultStoreWithCertAuth": {
  327. reason: "Should return a Vault provider successfully",
  328. args: args{
  329. store: makeValidSecretStoreWithCerts(),
  330. ns: "default",
  331. kube: clientfake.NewClientBuilder().WithObjects(&corev1.Secret{
  332. ObjectMeta: metav1.ObjectMeta{
  333. Name: tlsAuthCerts,
  334. Namespace: "default",
  335. },
  336. Data: map[string][]byte{
  337. tlsKey: secretClientKey,
  338. tlsCrt: clientCrt,
  339. },
  340. }).Build(),
  341. newClientFunc: fake.ClientWithLoginMock,
  342. },
  343. want: want{
  344. err: nil,
  345. },
  346. },
  347. "SuccessfulVaultStoreWithK8sCertSecret": {
  348. reason: "Should return a Vault provider with the cert from k8s",
  349. args: args{
  350. store: makeValidSecretStoreWithK8sCerts(true),
  351. ns: "default",
  352. kube: clientfake.NewClientBuilder().WithObjects(&corev1.Secret{
  353. ObjectMeta: metav1.ObjectMeta{
  354. Name: vaultCert,
  355. Namespace: "default",
  356. },
  357. Data: map[string][]byte{
  358. "cert": clientCrt,
  359. "token": secretData,
  360. },
  361. }).Build(),
  362. corev1: utilfake.NewCreateTokenMock().WithToken("ok"),
  363. newClientFunc: fake.ClientWithLoginMock,
  364. },
  365. want: want{
  366. err: nil,
  367. },
  368. },
  369. "GetCertNamespaceMissingError": {
  370. reason: "Should return an error if namespace is missing and is a ClusterSecretStore",
  371. args: args{
  372. store: makeInvalidClusterSecretStoreWithK8sCerts(),
  373. ns: "default",
  374. kube: clientfake.NewClientBuilder().Build(),
  375. },
  376. want: want{
  377. err: errors.New(errCANamespace),
  378. },
  379. },
  380. "GetCertSecretKeyMissingError": {
  381. reason: "Should return an error if the secret key is missing",
  382. args: args{
  383. store: makeValidSecretStoreWithK8sCerts(true),
  384. ns: "default",
  385. kube: clientfake.NewClientBuilder().WithObjects(&corev1.Secret{
  386. ObjectMeta: metav1.ObjectMeta{
  387. Name: vaultCert,
  388. Namespace: "default",
  389. },
  390. Data: map[string][]byte{},
  391. }).Build(),
  392. newClientFunc: fake.ClientWithLoginMock,
  393. },
  394. want: want{
  395. err: fmt.Errorf(errVaultCert, errors.New(`cannot find secret data for key: "cert"`)),
  396. },
  397. },
  398. "SuccessfulVaultStoreWithIamAuthSecret": {
  399. reason: "Should return a Vault provider successfully",
  400. args: args{
  401. store: makeValidSecretStoreWithIamAuthSecret(),
  402. ns: "default",
  403. kube: clientfake.NewClientBuilder().WithObjects(&corev1.Secret{
  404. ObjectMeta: metav1.ObjectMeta{
  405. Name: "vault-iam-creds-secret",
  406. Namespace: "default",
  407. },
  408. Data: map[string][]byte{
  409. "access-key": []byte("TESTING"),
  410. "secret-access-key": []byte("ABCDEF"),
  411. "secret-session-token": []byte("c2VjcmV0LXNlc3Npb24tdG9rZW4K"),
  412. },
  413. }).Build(),
  414. corev1: utilfake.NewCreateTokenMock().WithToken("ok"),
  415. newClientFunc: fake.ClientWithLoginMock,
  416. },
  417. want: want{
  418. err: nil,
  419. },
  420. },
  421. "SuccessfulVaultStoreWithK8sCertConfigMap": {
  422. reason: "Should return a Vault prodvider with the cert from k8s",
  423. args: args{
  424. store: makeValidSecretStoreWithK8sCerts(false),
  425. ns: "default",
  426. kube: clientfake.NewClientBuilder().WithObjects(&corev1.ConfigMap{
  427. ObjectMeta: metav1.ObjectMeta{
  428. Name: vaultCert,
  429. Namespace: "default",
  430. },
  431. Data: map[string]string{
  432. "cert": string(clientCrt),
  433. },
  434. }).Build(),
  435. corev1: utilfake.NewCreateTokenMock().WithToken("ok"),
  436. newClientFunc: fake.ClientWithLoginMock,
  437. },
  438. want: want{
  439. err: nil,
  440. },
  441. },
  442. "GetCertConfigMapMissingError": {
  443. reason: "Should return an error if the config map key is missing",
  444. args: args{
  445. store: makeValidSecretStoreWithK8sCerts(false),
  446. ns: "default",
  447. kube: clientfake.NewClientBuilder().WithObjects(&corev1.ServiceAccount{
  448. ObjectMeta: metav1.ObjectMeta{
  449. Name: "example-sa",
  450. Namespace: "default",
  451. },
  452. Secrets: []corev1.ObjectReference{
  453. {
  454. Name: tokenSecretName,
  455. },
  456. },
  457. }, &corev1.ConfigMap{
  458. ObjectMeta: metav1.ObjectMeta{
  459. Name: vaultCert,
  460. Namespace: "default",
  461. },
  462. Data: map[string]string{},
  463. }).Build(),
  464. newClientFunc: fake.ClientWithLoginMock,
  465. },
  466. want: want{
  467. err: fmt.Errorf(errConfigMapFmt, "cert"),
  468. },
  469. },
  470. "GetCertificateFormatError": {
  471. reason: "Should return error if client certificate is in wrong format.",
  472. args: args{
  473. store: makeValidSecretStoreWithCerts(),
  474. ns: "default",
  475. kube: clientfake.NewClientBuilder().WithObjects(&corev1.Secret{
  476. ObjectMeta: metav1.ObjectMeta{
  477. Name: tlsAuthCerts,
  478. Namespace: "default",
  479. },
  480. Data: map[string][]byte{
  481. tlsKey: secretClientKey,
  482. tlsCrt: []byte("cert with mistak"),
  483. },
  484. }).Build(),
  485. newClientFunc: fake.ClientWithLoginMock,
  486. },
  487. want: want{
  488. err: fmt.Errorf(errClientTLSAuth, "tls: failed to find any PEM data in certificate input"),
  489. },
  490. },
  491. "GetKeyFormatError": {
  492. reason: "Should return error if client key is in wrong format.",
  493. args: args{
  494. store: makeValidSecretStoreWithCerts(),
  495. ns: "default",
  496. kube: clientfake.NewClientBuilder().WithObjects(&corev1.Secret{
  497. ObjectMeta: metav1.ObjectMeta{
  498. Name: tlsAuthCerts,
  499. Namespace: "default",
  500. },
  501. Data: map[string][]byte{
  502. tlsKey: []byte("key with mistake"),
  503. tlsCrt: clientCrt,
  504. },
  505. }).Build(),
  506. newClientFunc: fake.ClientWithLoginMock,
  507. },
  508. want: want{
  509. err: fmt.Errorf(errClientTLSAuth, "tls: failed to find any PEM data in key input"),
  510. },
  511. },
  512. "ClientTlsInvalidCertificatesError": {
  513. reason: "Should return error if client key is in wrong format.",
  514. args: args{
  515. store: makeSecretStore(func(s *esv1beta1.SecretStore) {
  516. s.Spec.Provider.Vault.ClientTLS = esv1beta1.VaultClientTLS{
  517. CertSecretRef: &esmeta.SecretKeySelector{
  518. Name: tlsAuthCerts,
  519. },
  520. KeySecretRef: &esmeta.SecretKeySelector{
  521. Name: tlsAuthCerts,
  522. },
  523. }
  524. }),
  525. ns: "default",
  526. kube: clientfake.NewClientBuilder().WithObjects(&corev1.Secret{
  527. ObjectMeta: metav1.ObjectMeta{
  528. Name: tlsAuthCerts,
  529. Namespace: "default",
  530. },
  531. Data: map[string][]byte{
  532. tlsKey: []byte("key with mistake"),
  533. tlsCrt: clientCrt,
  534. },
  535. }).Build(),
  536. corev1: utilfake.NewCreateTokenMock().WithToken("ok"),
  537. newClientFunc: fake.ClientWithLoginMock,
  538. },
  539. want: want{
  540. err: fmt.Errorf(errClientTLSAuth, "tls: failed to find any PEM data in key input"),
  541. },
  542. },
  543. "SuccessfulVaultStoreValidClientTls": {
  544. reason: "Should return a Vault provider with the cert from k8s",
  545. args: args{
  546. store: makeSecretStore(func(s *esv1beta1.SecretStore) {
  547. s.Spec.Provider.Vault.ClientTLS = esv1beta1.VaultClientTLS{
  548. CertSecretRef: &esmeta.SecretKeySelector{
  549. Name: tlsAuthCerts,
  550. },
  551. KeySecretRef: &esmeta.SecretKeySelector{
  552. Name: tlsAuthCerts,
  553. },
  554. }
  555. }),
  556. ns: "default",
  557. kube: clientfake.NewClientBuilder().WithObjects(&corev1.Secret{
  558. ObjectMeta: metav1.ObjectMeta{
  559. Name: tlsAuthCerts,
  560. Namespace: "default",
  561. },
  562. Data: map[string][]byte{
  563. tlsKey: secretClientKey,
  564. tlsCrt: clientCrt,
  565. },
  566. }).Build(),
  567. corev1: utilfake.NewCreateTokenMock().WithToken("ok"),
  568. newClientFunc: fake.ClientWithLoginMock,
  569. },
  570. want: want{
  571. err: nil,
  572. },
  573. },
  574. "SuccessfulVaultStoreWithSecretRef": {
  575. reason: "Should return a Vault provider with secret ref auth",
  576. args: args{
  577. store: makeClusterSecretStore(func(s *esv1beta1.SecretStore) {
  578. s.Spec.Provider.Vault.Auth.Kubernetes = nil
  579. s.Spec.Provider.Vault.Auth.TokenSecretRef = &esmeta.SecretKeySelector{
  580. Name: "vault-token",
  581. Namespace: ptr.To("default"),
  582. Key: "token",
  583. }
  584. }),
  585. kube: clientfake.NewClientBuilder().WithObjects(&corev1.Secret{
  586. ObjectMeta: metav1.ObjectMeta{
  587. Name: "vault-token",
  588. Namespace: "default",
  589. },
  590. Data: map[string][]byte{
  591. "token": []byte("token"),
  592. },
  593. }).Build(),
  594. // no need to mock the secret as it is not used
  595. newClientFunc: fake.ClientWithLoginMock,
  596. },
  597. want: want{},
  598. },
  599. "SuccessfulVaultStoreWithApproleRef": {
  600. reason: "Should return a Vault provider with approle auth",
  601. args: args{
  602. store: makeSecretStore(func(s *esv1beta1.SecretStore) {
  603. s.Spec.Provider.Vault.Auth.Kubernetes = nil
  604. s.Spec.Provider.Vault.Auth.AppRole = &esv1beta1.VaultAppRole{
  605. SecretRef: esmeta.SecretKeySelector{
  606. Name: "vault-secret-id",
  607. Key: "secret-id",
  608. },
  609. RoleRef: &esmeta.SecretKeySelector{
  610. Name: "vault-secret-id",
  611. Key: "approle",
  612. },
  613. }
  614. }),
  615. ns: "default",
  616. kube: clientfake.NewClientBuilder().WithObjects(&corev1.Secret{
  617. ObjectMeta: metav1.ObjectMeta{
  618. Name: "vault-secret-id",
  619. Namespace: "default",
  620. },
  621. Data: map[string][]byte{
  622. "secret-id": []byte("myid"),
  623. "approle": []byte("myrole"),
  624. },
  625. }).Build(),
  626. // no need to mock the secret as it is not used
  627. newClientFunc: fake.ClientWithLoginMock,
  628. },
  629. want: want{},
  630. },
  631. "SuccessfulVaultStoreWithSecretRefAndReferentSpec": {
  632. reason: "Should return a Vault provider with secret ref auth",
  633. args: args{
  634. store: makeClusterSecretStore(func(s *esv1beta1.SecretStore) {
  635. s.Spec.Provider.Vault.Auth.TokenSecretRef = &esmeta.SecretKeySelector{
  636. Name: "vault-token",
  637. Key: "token",
  638. }
  639. }),
  640. // no need to mock the secret as it is not used
  641. newClientFunc: fake.ClientWithLoginMock,
  642. },
  643. want: want{},
  644. },
  645. "SuccessfulVaultStoreWithJwtAuthAndReferentSpec": {
  646. reason: "Should return a Vault provider with jwt auth",
  647. args: args{
  648. store: makeClusterSecretStore(func(s *esv1beta1.SecretStore) {
  649. s.Spec.Provider.Vault.Auth.Kubernetes = nil
  650. s.Spec.Provider.Vault.Auth.Jwt = &esv1beta1.VaultJwtAuth{
  651. Role: "test-role",
  652. SecretRef: &esmeta.SecretKeySelector{
  653. Name: "vault-token",
  654. },
  655. }
  656. }),
  657. // no need to mock the secret as it is not used
  658. newClientFunc: fake.ClientWithLoginMock,
  659. },
  660. want: want{},
  661. },
  662. }
  663. for name, tc := range cases {
  664. t.Run(name, func(t *testing.T) {
  665. vaultTest(t, name, tc)
  666. })
  667. }
  668. }
  669. func vaultTest(t *testing.T, _ string, tc testCase) {
  670. prov := &Provider{
  671. NewVaultClient: tc.args.newClientFunc,
  672. }
  673. if tc.args.newClientFunc == nil {
  674. prov.NewVaultClient = NewVaultClient
  675. }
  676. _, err := prov.newClient(context.Background(), tc.args.store, tc.args.kube, tc.args.corev1, tc.args.ns)
  677. if diff := cmp.Diff(tc.want.err, err, EquateErrors()); diff != "" {
  678. t.Errorf("\n%s\nvault.New(...): -want error, +got error:\n%s", tc.reason, diff)
  679. }
  680. }