manager_test.go 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384
  1. /*
  2. Copyright © The ESO Authors
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. https://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package clientmanager
  14. import (
  15. "context"
  16. "crypto/rand"
  17. "crypto/rsa"
  18. "crypto/tls"
  19. "crypto/x509"
  20. "crypto/x509/pkix"
  21. "encoding/pem"
  22. "math/big"
  23. "net"
  24. "sync"
  25. "testing"
  26. "time"
  27. "github.com/go-logr/logr"
  28. "github.com/prometheus/client_golang/prometheus"
  29. dto "github.com/prometheus/client_model/go"
  30. "github.com/stretchr/testify/assert"
  31. "github.com/stretchr/testify/require"
  32. "google.golang.org/grpc"
  33. "google.golang.org/grpc/credentials"
  34. corev1 "k8s.io/api/core/v1"
  35. apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
  36. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  37. "k8s.io/apimachinery/pkg/runtime"
  38. utilruntime "k8s.io/apimachinery/pkg/util/runtime"
  39. clientgoscheme "k8s.io/client-go/kubernetes/scheme"
  40. "sigs.k8s.io/controller-runtime/pkg/client"
  41. fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
  42. "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
  43. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  44. pb "github.com/external-secrets/external-secrets/proto/provider"
  45. providergrpc "github.com/external-secrets/external-secrets/providers/v2/common/grpc"
  46. )
  47. func TestManagerGet(t *testing.T) {
  48. scheme := runtime.NewScheme()
  49. // add kubernetes schemes
  50. utilruntime.Must(clientgoscheme.AddToScheme(scheme))
  51. utilruntime.Must(apiextensionsv1.AddToScheme(scheme))
  52. // add external-secrets schemes
  53. utilruntime.Must(esv1.AddToScheme(scheme))
  54. // We have a test provider to control
  55. // the behavior of the NewClient func.
  56. fakeProvider := &WrapProvider{}
  57. esv1.ForceRegister(fakeProvider, &esv1.SecretStoreProvider{
  58. AWS: &esv1.AWSProvider{},
  59. }, esv1.MaintenanceStatusMaintained)
  60. // fake clients are re-used to compare the
  61. // in-memory reference
  62. clientA := &MockFakeClient{id: "1"}
  63. clientB := &MockFakeClient{id: "2"}
  64. const testNamespace = "foo"
  65. readyStatus := esv1.SecretStoreStatus{
  66. Conditions: []esv1.SecretStoreStatusCondition{
  67. {
  68. Type: esv1.SecretStoreReady,
  69. Status: corev1.ConditionTrue,
  70. },
  71. },
  72. }
  73. fakeSpec := esv1.SecretStoreSpec{
  74. Provider: &esv1.SecretStoreProvider{
  75. AWS: &esv1.AWSProvider{},
  76. },
  77. }
  78. defaultStore := &esv1.SecretStore{
  79. TypeMeta: metav1.TypeMeta{Kind: esv1.SecretStoreKind},
  80. ObjectMeta: metav1.ObjectMeta{
  81. Name: "foo",
  82. Namespace: testNamespace,
  83. },
  84. Spec: fakeSpec,
  85. Status: readyStatus,
  86. }
  87. otherStore := &esv1.SecretStore{
  88. TypeMeta: metav1.TypeMeta{Kind: esv1.SecretStoreKind},
  89. ObjectMeta: metav1.ObjectMeta{
  90. Name: "other",
  91. Namespace: testNamespace,
  92. },
  93. Spec: fakeSpec,
  94. Status: readyStatus,
  95. }
  96. var mgr *Manager
  97. provKey := storeKey(fakeProvider)
  98. type fields struct {
  99. client client.Client
  100. clientMap map[clientKey]*clientVal
  101. }
  102. type args struct {
  103. storeRef esv1.SecretStoreRef
  104. namespace string
  105. sourceRef *esv1.StoreGeneratorSourceRef
  106. }
  107. tests := []struct {
  108. name string
  109. fields fields
  110. args args
  111. clientConstructor func(
  112. ctx context.Context,
  113. store esv1.GenericStore,
  114. kube client.Client,
  115. namespace string) (esv1.SecretsClient, error)
  116. verify func(esv1.SecretsClient)
  117. afterClose func()
  118. want esv1.SecretsClient
  119. wantErr bool
  120. }{
  121. {
  122. name: "creates a new client from storeRef and stores it",
  123. wantErr: false,
  124. fields: fields{
  125. client: fakeclient.NewClientBuilder().
  126. WithScheme(scheme).
  127. WithObjects(defaultStore).
  128. Build(),
  129. clientMap: make(map[clientKey]*clientVal),
  130. },
  131. args: args{
  132. storeRef: esv1.SecretStoreRef{
  133. Name: defaultStore.Name,
  134. Kind: esv1.SecretStoreKind,
  135. },
  136. namespace: defaultStore.Namespace,
  137. sourceRef: nil,
  138. },
  139. clientConstructor: func(_ context.Context, _ esv1.GenericStore, _ client.Client, _ string) (esv1.SecretsClient, error) {
  140. return clientA, nil
  141. },
  142. verify: func(sc esv1.SecretsClient) {
  143. // we now must have this provider in the clientMap
  144. // and it mustbe the client defined in clientConstructor
  145. assert.NotNil(t, sc)
  146. c, ok := mgr.clientMap[provKey]
  147. require.True(t, ok)
  148. assert.Same(t, c.client, clientA)
  149. },
  150. afterClose: func() {
  151. v, ok := mgr.clientMap[provKey]
  152. assert.False(t, ok)
  153. assert.Nil(t, v)
  154. },
  155. },
  156. {
  157. name: "creates a new client using both storeRef and sourceRef",
  158. wantErr: false,
  159. fields: fields{
  160. client: fakeclient.NewClientBuilder().
  161. WithScheme(scheme).
  162. WithObjects(otherStore).
  163. Build(),
  164. clientMap: make(map[clientKey]*clientVal),
  165. },
  166. args: args{
  167. storeRef: esv1.SecretStoreRef{
  168. Name: defaultStore.Name,
  169. Kind: esv1.SecretStoreKind,
  170. },
  171. // this should take precedence
  172. sourceRef: &esv1.StoreGeneratorSourceRef{
  173. SecretStoreRef: &esv1.SecretStoreRef{
  174. Name: otherStore.Name,
  175. Kind: esv1.SecretStoreKind,
  176. },
  177. },
  178. namespace: defaultStore.Namespace,
  179. },
  180. clientConstructor: func(_ context.Context, _ esv1.GenericStore, _ client.Client, _ string) (esv1.SecretsClient, error) {
  181. return clientB, nil
  182. },
  183. verify: func(sc esv1.SecretsClient) {
  184. // we now must have this provider in the clientMap
  185. // and it mustbe the client defined in clientConstructor
  186. assert.NotNil(t, sc)
  187. c, ok := mgr.clientMap[provKey]
  188. assert.True(t, ok)
  189. assert.Same(t, c.client, clientB)
  190. },
  191. afterClose: func() {
  192. v, ok := mgr.clientMap[provKey]
  193. assert.False(t, ok)
  194. assert.True(t, clientB.closeCalled)
  195. assert.Nil(t, v)
  196. },
  197. },
  198. {
  199. name: "retrieve cached client when store matches",
  200. wantErr: false,
  201. fields: fields{
  202. client: fakeclient.NewClientBuilder().
  203. WithScheme(scheme).
  204. WithObjects(defaultStore).
  205. Build(),
  206. clientMap: map[clientKey]*clientVal{
  207. provKey: {
  208. client: clientA,
  209. store: defaultStore,
  210. },
  211. },
  212. },
  213. args: args{
  214. storeRef: esv1.SecretStoreRef{
  215. Name: defaultStore.Name,
  216. Kind: esv1.SecretStoreKind,
  217. },
  218. namespace: defaultStore.Namespace,
  219. sourceRef: nil,
  220. },
  221. clientConstructor: func(_ context.Context, _ esv1.GenericStore, _ client.Client, _ string) (esv1.SecretsClient, error) {
  222. // constructor should not be called,
  223. // the client from the cache should be returned instead
  224. t.Fail()
  225. return nil, nil
  226. },
  227. verify: func(sc esv1.SecretsClient) {
  228. // verify that the secretsClient is the one from cache
  229. assert.NotNil(t, sc)
  230. c, ok := mgr.clientMap[provKey]
  231. assert.True(t, ok)
  232. assert.Same(t, c.client, clientA)
  233. assert.Same(t, sc, clientA)
  234. },
  235. afterClose: func() {
  236. v, ok := mgr.clientMap[provKey]
  237. assert.False(t, ok)
  238. assert.True(t, clientA.closeCalled)
  239. assert.Nil(t, v)
  240. },
  241. },
  242. {
  243. name: "create new client when store doesn't match",
  244. wantErr: false,
  245. fields: fields{
  246. client: fakeclient.NewClientBuilder().
  247. WithScheme(scheme).
  248. WithObjects(otherStore).
  249. Build(),
  250. clientMap: map[clientKey]*clientVal{
  251. provKey: {
  252. // we have clientA in cache pointing at defaultStore
  253. client: clientA,
  254. store: defaultStore,
  255. },
  256. },
  257. },
  258. args: args{
  259. storeRef: esv1.SecretStoreRef{
  260. Name: otherStore.Name,
  261. Kind: esv1.SecretStoreKind,
  262. },
  263. namespace: otherStore.Namespace,
  264. sourceRef: nil,
  265. },
  266. clientConstructor: func(_ context.Context, _ esv1.GenericStore, _ client.Client, _ string) (esv1.SecretsClient, error) {
  267. // because there is a store mismatch
  268. // we create a new client
  269. return clientB, nil
  270. },
  271. verify: func(sc esv1.SecretsClient) {
  272. // verify that SecretsClient is NOT the one from cache
  273. assert.NotNil(t, sc)
  274. c, ok := mgr.clientMap[provKey]
  275. assert.True(t, ok)
  276. assert.Same(t, c.client, clientB)
  277. assert.Same(t, sc, clientB)
  278. assert.True(t, clientA.closeCalled)
  279. },
  280. afterClose: func() {
  281. v, ok := mgr.clientMap[provKey]
  282. assert.False(t, ok)
  283. assert.True(t, clientB.closeCalled)
  284. assert.Nil(t, v)
  285. },
  286. },
  287. }
  288. for _, tt := range tests {
  289. t.Run(tt.name, func(t *testing.T) {
  290. mgr = &Manager{
  291. log: logr.Discard(),
  292. client: tt.fields.client,
  293. enableFloodgate: true,
  294. clientMap: tt.fields.clientMap,
  295. }
  296. fakeProvider.newClientFunc = tt.clientConstructor
  297. clientA.closeCalled = false
  298. clientB.closeCalled = false
  299. got, err := mgr.Get(context.Background(), tt.args.storeRef, tt.args.namespace, tt.args.sourceRef)
  300. if (err != nil) != tt.wantErr {
  301. t.Errorf("Manager.Get() error = %v, wantErr %v", err, tt.wantErr)
  302. return
  303. }
  304. tt.verify(got)
  305. mgr.Close(context.Background())
  306. tt.afterClose()
  307. })
  308. }
  309. }
  310. func TestShouldProcessSecret(t *testing.T) {
  311. scheme := runtime.NewScheme()
  312. // add kubernetes schemes
  313. utilruntime.Must(clientgoscheme.AddToScheme(scheme))
  314. utilruntime.Must(apiextensionsv1.AddToScheme(scheme))
  315. // add external-secrets schemes
  316. utilruntime.Must(esv1.AddToScheme(scheme))
  317. testNamespace := "test-a"
  318. testCases := []struct {
  319. name string
  320. conditions []esv1.ClusterSecretStoreCondition
  321. namespace *corev1.Namespace
  322. wantErr string
  323. want bool
  324. }{
  325. {
  326. name: "processes a regex condition",
  327. conditions: []esv1.ClusterSecretStoreCondition{
  328. {
  329. NamespaceRegexes: []string{`test-*`},
  330. },
  331. },
  332. namespace: &corev1.Namespace{
  333. ObjectMeta: metav1.ObjectMeta{
  334. Name: testNamespace,
  335. },
  336. },
  337. want: true,
  338. },
  339. {
  340. name: "process multiple regexes",
  341. conditions: []esv1.ClusterSecretStoreCondition{
  342. {
  343. NamespaceRegexes: []string{`nope`, `test-*`},
  344. },
  345. },
  346. namespace: &corev1.Namespace{
  347. ObjectMeta: metav1.ObjectMeta{
  348. Name: testNamespace,
  349. },
  350. },
  351. want: true,
  352. },
  353. {
  354. name: "shouldn't process if nothing matches",
  355. conditions: []esv1.ClusterSecretStoreCondition{
  356. {
  357. NamespaceRegexes: []string{`nope`},
  358. },
  359. },
  360. namespace: &corev1.Namespace{
  361. ObjectMeta: metav1.ObjectMeta{
  362. Name: testNamespace,
  363. },
  364. },
  365. want: false,
  366. },
  367. }
  368. for _, tt := range testCases {
  369. t.Run(tt.name, func(t *testing.T) {
  370. fakeSpec := esv1.SecretStoreSpec{
  371. Conditions: tt.conditions,
  372. }
  373. defaultStore := &esv1.ClusterSecretStore{
  374. TypeMeta: metav1.TypeMeta{Kind: esv1.ClusterSecretStoreKind},
  375. ObjectMeta: metav1.ObjectMeta{
  376. Name: "foo",
  377. Namespace: tt.namespace.Name,
  378. },
  379. Spec: fakeSpec,
  380. }
  381. client := fakeclient.NewClientBuilder().WithScheme(scheme).WithObjects(defaultStore, tt.namespace).Build()
  382. clientMap := make(map[clientKey]*clientVal)
  383. mgr := &Manager{
  384. log: logr.Discard(),
  385. client: client,
  386. enableFloodgate: true,
  387. clientMap: clientMap,
  388. }
  389. got, err := mgr.shouldProcessSecret(defaultStore, tt.namespace.Name)
  390. require.NoError(t, err)
  391. assert.Equal(t, tt.want, got)
  392. })
  393. }
  394. }
  395. func TestGetV2ProviderFeatureGate(t *testing.T) {
  396. previous := V2ProvidersEnabled()
  397. SetV2ProvidersEnabled(false)
  398. t.Cleanup(func() {
  399. SetV2ProvidersEnabled(previous)
  400. })
  401. mgr := NewManager(nil, "default", false)
  402. _, err := mgr.Get(context.Background(), esv1.SecretStoreRef{
  403. Name: "example-provider",
  404. Kind: esv1.ProviderKindStr,
  405. }, "default", nil)
  406. require.Error(t, err)
  407. assert.ErrorContains(t, err, "v2 provider support is disabled")
  408. }
  409. func TestGetV2ProviderFeatureGateFromSourceRef(t *testing.T) {
  410. previous := V2ProvidersEnabled()
  411. SetV2ProvidersEnabled(false)
  412. t.Cleanup(func() {
  413. SetV2ProvidersEnabled(previous)
  414. })
  415. mgr := NewManager(nil, "default", false)
  416. _, err := mgr.Get(context.Background(), esv1.SecretStoreRef{
  417. Name: "example-store",
  418. Kind: esv1.SecretStoreKind,
  419. }, "default", &esv1.StoreGeneratorSourceRef{
  420. SecretStoreRef: &esv1.SecretStoreRef{
  421. Name: "example-provider",
  422. Kind: esv1.ProviderKindStr,
  423. },
  424. })
  425. require.Error(t, err)
  426. assert.ErrorContains(t, err, "v2 provider support is disabled")
  427. }
  428. func TestGetV2ClusterProviderManifestScopeUsesManifestNamespaceForTLS(t *testing.T) {
  429. previous := V2ProvidersEnabled()
  430. SetV2ProvidersEnabled(true)
  431. t.Cleanup(func() {
  432. SetV2ProvidersEnabled(previous)
  433. })
  434. resetGlobalV2ConnectionPoolForTest(t)
  435. scheme := newManagerTestScheme(t)
  436. server, address, tlsSecret := newRecordingProviderServer(t)
  437. const manifestNamespace = "tenant-a"
  438. const referencedConfigNamespace = "provider-config-ns"
  439. clusterProvider := &esv1.ClusterProvider{
  440. ObjectMeta: metav1.ObjectMeta{
  441. Name: "cluster-provider",
  442. },
  443. Spec: esv1.ClusterProviderSpec{
  444. Config: esv1.ProviderConfig{
  445. Address: address,
  446. ProviderRef: esv1.ProviderReference{
  447. APIVersion: "provider.external-secrets.io/v2alpha1",
  448. Kind: "Kubernetes",
  449. Name: "kubernetes-backend",
  450. },
  451. },
  452. AuthenticationScope: esv1.AuthenticationScopeManifestNamespace,
  453. Conditions: []esv1.ClusterSecretStoreCondition{
  454. {
  455. Namespaces: []string{manifestNamespace},
  456. },
  457. },
  458. },
  459. }
  460. kubeClient := fakeclient.NewClientBuilder().
  461. WithScheme(scheme).
  462. WithObjects(
  463. &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
  464. Name: manifestNamespace,
  465. Labels: map[string]string{
  466. "kubernetes.io/metadata.name": manifestNamespace,
  467. },
  468. }},
  469. &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: referencedConfigNamespace}},
  470. clusterProvider,
  471. &corev1.Secret{
  472. ObjectMeta: metav1.ObjectMeta{
  473. Name: "external-secrets-provider-tls",
  474. Namespace: manifestNamespace,
  475. },
  476. Data: tlsSecret,
  477. },
  478. ).
  479. Build()
  480. mgr := NewManager(kubeClient, "default", false)
  481. client, err := mgr.Get(context.Background(), esv1.SecretStoreRef{
  482. Name: clusterProvider.Name,
  483. Kind: esv1.ClusterProviderKindStr,
  484. }, manifestNamespace, nil)
  485. require.NoError(t, err)
  486. result, err := client.Validate()
  487. require.NoError(t, err)
  488. assert.Equal(t, esv1.ValidationResultReady, result)
  489. req := server.LastValidateRequest()
  490. require.NotNil(t, req)
  491. assert.Equal(t, manifestNamespace, req.SourceNamespace)
  492. require.NotNil(t, req.ProviderRef)
  493. assert.Equal(t, "kubernetes-backend", req.ProviderRef.Name)
  494. assert.Equal(t, "", req.ProviderRef.Namespace)
  495. assert.Equal(t, esv1.ClusterProviderKindStr, req.ProviderRef.StoreRefKind)
  496. require.Len(t, mgr.v2PooledConnections, 1)
  497. }
  498. func TestGetV2ClusterProviderRejectsProviderNamespaceWithoutNamespace(t *testing.T) {
  499. previous := V2ProvidersEnabled()
  500. SetV2ProvidersEnabled(true)
  501. t.Cleanup(func() {
  502. SetV2ProvidersEnabled(previous)
  503. })
  504. resetGlobalV2ConnectionPoolForTest(t)
  505. scheme := newManagerTestScheme(t)
  506. const manifestNamespace = "tenant-a"
  507. clusterProvider := &esv1.ClusterProvider{
  508. ObjectMeta: metav1.ObjectMeta{
  509. Name: "cluster-provider",
  510. },
  511. Spec: esv1.ClusterProviderSpec{
  512. Config: esv1.ProviderConfig{
  513. Address: "127.0.0.1:9443",
  514. ProviderRef: esv1.ProviderReference{
  515. APIVersion: "provider.external-secrets.io/v2alpha1",
  516. Kind: "Kubernetes",
  517. Name: "kubernetes-backend",
  518. },
  519. },
  520. AuthenticationScope: esv1.AuthenticationScopeProviderNamespace,
  521. },
  522. }
  523. kubeClient := fakeclient.NewClientBuilder().
  524. WithScheme(scheme).
  525. WithObjects(
  526. &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
  527. Name: manifestNamespace,
  528. Labels: map[string]string{
  529. "kubernetes.io/metadata.name": manifestNamespace,
  530. },
  531. }},
  532. clusterProvider,
  533. ).
  534. Build()
  535. mgr := NewManager(kubeClient, "default", false)
  536. _, err := mgr.Get(context.Background(), esv1.SecretStoreRef{
  537. Name: clusterProvider.Name,
  538. Kind: esv1.ClusterProviderKindStr,
  539. }, manifestNamespace, nil)
  540. require.Error(t, err)
  541. assert.ErrorContains(t, err, "authenticationScope=ProviderNamespace")
  542. assert.ErrorContains(t, err, "providerRef.namespace is empty")
  543. }
  544. func TestGetV2ClusterProviderProviderScopeUsesProviderNamespaceForTLS(t *testing.T) {
  545. previous := V2ProvidersEnabled()
  546. SetV2ProvidersEnabled(true)
  547. t.Cleanup(func() {
  548. SetV2ProvidersEnabled(previous)
  549. })
  550. resetGlobalV2ConnectionPoolForTest(t)
  551. scheme := newManagerTestScheme(t)
  552. server, address, tlsSecret := newRecordingProviderServer(t)
  553. const manifestNamespace = "tenant-a"
  554. const referencedConfigNamespace = "provider-config-ns"
  555. clusterProvider := &esv1.ClusterProvider{
  556. ObjectMeta: metav1.ObjectMeta{
  557. Name: "cluster-provider",
  558. },
  559. Spec: esv1.ClusterProviderSpec{
  560. Config: esv1.ProviderConfig{
  561. Address: address,
  562. ProviderRef: esv1.ProviderReference{
  563. APIVersion: "provider.external-secrets.io/v2alpha1",
  564. Kind: "Kubernetes",
  565. Name: "kubernetes-backend",
  566. Namespace: referencedConfigNamespace,
  567. },
  568. },
  569. AuthenticationScope: esv1.AuthenticationScopeProviderNamespace,
  570. Conditions: []esv1.ClusterSecretStoreCondition{
  571. {
  572. Namespaces: []string{manifestNamespace},
  573. },
  574. },
  575. },
  576. }
  577. kubeClient := fakeclient.NewClientBuilder().
  578. WithScheme(scheme).
  579. WithObjects(
  580. &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
  581. Name: manifestNamespace,
  582. Labels: map[string]string{
  583. "kubernetes.io/metadata.name": manifestNamespace,
  584. },
  585. }},
  586. clusterProvider,
  587. &corev1.Secret{
  588. ObjectMeta: metav1.ObjectMeta{
  589. Name: "external-secrets-provider-tls",
  590. Namespace: referencedConfigNamespace,
  591. },
  592. Data: tlsSecret,
  593. },
  594. ).
  595. Build()
  596. mgr := NewManager(kubeClient, "default", false)
  597. client, err := mgr.Get(context.Background(), esv1.SecretStoreRef{
  598. Name: clusterProvider.Name,
  599. Kind: esv1.ClusterProviderKindStr,
  600. }, manifestNamespace, nil)
  601. require.NoError(t, err)
  602. result, err := client.Validate()
  603. require.NoError(t, err)
  604. assert.Equal(t, esv1.ValidationResultReady, result)
  605. req := server.LastValidateRequest()
  606. require.NotNil(t, req)
  607. assert.Equal(t, referencedConfigNamespace, req.SourceNamespace)
  608. require.NotNil(t, req.ProviderRef)
  609. assert.Equal(t, "kubernetes-backend", req.ProviderRef.Name)
  610. assert.Equal(t, referencedConfigNamespace, req.ProviderRef.Namespace)
  611. assert.Equal(t, esv1.ClusterProviderKindStr, req.ProviderRef.StoreRefKind)
  612. require.Len(t, mgr.v2PooledConnections, 1)
  613. }
  614. func TestGetV2ClusterProviderRejectsDeniedNamespace(t *testing.T) {
  615. previous := V2ProvidersEnabled()
  616. SetV2ProvidersEnabled(true)
  617. t.Cleanup(func() {
  618. SetV2ProvidersEnabled(previous)
  619. })
  620. resetGlobalV2ConnectionPoolForTest(t)
  621. scheme := newManagerTestScheme(t)
  622. const manifestNamespace = "tenant-a"
  623. clusterProvider := &esv1.ClusterProvider{
  624. ObjectMeta: metav1.ObjectMeta{
  625. Name: "cluster-provider",
  626. },
  627. Spec: esv1.ClusterProviderSpec{
  628. Config: esv1.ProviderConfig{
  629. Address: "127.0.0.1:9443",
  630. ProviderRef: esv1.ProviderReference{
  631. APIVersion: "provider.external-secrets.io/v2alpha1",
  632. Kind: "Kubernetes",
  633. Name: "kubernetes-backend",
  634. Namespace: "provider-config-ns",
  635. },
  636. },
  637. Conditions: []esv1.ClusterSecretStoreCondition{
  638. {
  639. NamespaceRegexes: []string{`other-.*`},
  640. },
  641. },
  642. },
  643. }
  644. kubeClient := fakeclient.NewClientBuilder().
  645. WithScheme(scheme).
  646. WithObjects(
  647. &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
  648. Name: manifestNamespace,
  649. Labels: map[string]string{
  650. "kubernetes.io/metadata.name": manifestNamespace,
  651. },
  652. }},
  653. clusterProvider,
  654. ).
  655. Build()
  656. mgr := NewManager(kubeClient, "default", false)
  657. _, err := mgr.Get(context.Background(), esv1.SecretStoreRef{
  658. Name: clusterProvider.Name,
  659. Kind: esv1.ClusterProviderKindStr,
  660. }, manifestNamespace, nil)
  661. require.Error(t, err)
  662. assert.ErrorContains(t, err, "denied by spec.conditions")
  663. }
  664. func TestGetV2ProviderUsesManifestNamespaceAndDistinctCacheEntriesPerNamespace(t *testing.T) {
  665. previous := V2ProvidersEnabled()
  666. SetV2ProvidersEnabled(true)
  667. t.Cleanup(func() {
  668. SetV2ProvidersEnabled(previous)
  669. })
  670. registry := installGlobalV2ConnectionPoolForTest(t)
  671. scheme := newManagerTestScheme(t)
  672. server, address, tlsSecret := newRecordingProviderServer(t)
  673. const providerName = "provider"
  674. const firstManifestNamespace = "tenant-a"
  675. const secondManifestNamespace = "tenant-b"
  676. const referencedConfigNamespace = "provider-config-ns"
  677. providerA := &esv1.Provider{
  678. ObjectMeta: metav1.ObjectMeta{
  679. Name: providerName,
  680. Namespace: firstManifestNamespace,
  681. Generation: 1,
  682. },
  683. Spec: esv1.ProviderSpec{
  684. Config: esv1.ProviderConfig{
  685. Address: address,
  686. ProviderRef: esv1.ProviderReference{
  687. APIVersion: "provider.external-secrets.io/v2alpha1",
  688. Kind: "Kubernetes",
  689. Name: "kubernetes-backend",
  690. Namespace: referencedConfigNamespace,
  691. },
  692. },
  693. },
  694. }
  695. providerB := &esv1.Provider{
  696. ObjectMeta: metav1.ObjectMeta{
  697. Name: providerName,
  698. Namespace: secondManifestNamespace,
  699. Generation: 1,
  700. },
  701. Spec: esv1.ProviderSpec{
  702. Config: providerA.Spec.Config,
  703. },
  704. }
  705. kubeClient := fakeclient.NewClientBuilder().
  706. WithScheme(scheme).
  707. WithObjects(
  708. &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
  709. Name: firstManifestNamespace,
  710. Labels: map[string]string{
  711. "kubernetes.io/metadata.name": firstManifestNamespace,
  712. },
  713. }},
  714. &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
  715. Name: secondManifestNamespace,
  716. Labels: map[string]string{
  717. "kubernetes.io/metadata.name": secondManifestNamespace,
  718. },
  719. }},
  720. &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: referencedConfigNamespace}},
  721. providerA,
  722. providerB,
  723. &corev1.Secret{
  724. ObjectMeta: metav1.ObjectMeta{
  725. Name: "external-secrets-provider-tls",
  726. Namespace: firstManifestNamespace,
  727. },
  728. Data: tlsSecret,
  729. },
  730. &corev1.Secret{
  731. ObjectMeta: metav1.ObjectMeta{
  732. Name: "external-secrets-provider-tls",
  733. Namespace: secondManifestNamespace,
  734. },
  735. Data: tlsSecret,
  736. },
  737. ).
  738. Build()
  739. mgr := NewManager(kubeClient, "default", false)
  740. firstClient, err := mgr.Get(context.Background(), esv1.SecretStoreRef{
  741. Name: providerName,
  742. Kind: esv1.ProviderKindStr,
  743. }, firstManifestNamespace, nil)
  744. require.NoError(t, err)
  745. ready, err := firstClient.Validate()
  746. require.NoError(t, err)
  747. assert.Equal(t, esv1.ValidationResultReady, ready)
  748. firstReq := server.LastValidateRequest()
  749. require.NotNil(t, firstReq)
  750. assert.Equal(t, firstManifestNamespace, firstReq.SourceNamespace)
  751. secondClient, err := mgr.Get(context.Background(), esv1.SecretStoreRef{
  752. Name: providerName,
  753. Kind: esv1.ProviderKindStr,
  754. }, secondManifestNamespace, nil)
  755. require.NoError(t, err)
  756. ready, err = secondClient.Validate()
  757. require.NoError(t, err)
  758. assert.Equal(t, esv1.ValidationResultReady, ready)
  759. secondReq := server.LastValidateRequest()
  760. require.NotNil(t, secondReq)
  761. assert.Equal(t, secondManifestNamespace, secondReq.SourceNamespace)
  762. assert.NotSame(t, firstClient, secondClient)
  763. require.Len(t, mgr.clientMap, 2)
  764. require.Len(t, mgr.v2PooledConnections, 2)
  765. assertPoolMetricEventually(t, registry, "grpc_pool_connections_active", address, true, 1)
  766. assertPoolMetricEventually(t, registry, "grpc_pool_connections_total", address, true, 1)
  767. require.NoError(t, mgr.Close(context.Background()))
  768. assert.Empty(t, mgr.clientMap)
  769. assert.Empty(t, mgr.v2PooledConnections)
  770. assertPoolMetricEventually(t, registry, "grpc_pool_connections_active", address, true, 0)
  771. assertPoolMetricEventually(t, registry, "grpc_pool_connections_idle", address, true, 1)
  772. assertPoolMetricEventually(t, registry, "grpc_pool_connections_total", address, true, 1)
  773. assert.Equal(t, 2, server.ValidateCallCount())
  774. }
  775. func TestGetV2ProviderInvalidatesGenerationCacheAndReleasesPoolReferences(t *testing.T) {
  776. previous := V2ProvidersEnabled()
  777. SetV2ProvidersEnabled(true)
  778. t.Cleanup(func() {
  779. SetV2ProvidersEnabled(previous)
  780. })
  781. registry := installGlobalV2ConnectionPoolForTest(t)
  782. scheme := newManagerTestScheme(t)
  783. server, address, tlsSecret := newRecordingProviderServer(t)
  784. const manifestNamespace = "tenant-a"
  785. const referencedConfigNamespace = "provider-config-ns"
  786. provider := &esv1.Provider{
  787. ObjectMeta: metav1.ObjectMeta{
  788. Name: "provider",
  789. Namespace: manifestNamespace,
  790. Generation: 1,
  791. },
  792. Spec: esv1.ProviderSpec{
  793. Config: esv1.ProviderConfig{
  794. Address: address,
  795. ProviderRef: esv1.ProviderReference{
  796. APIVersion: "provider.external-secrets.io/v2alpha1",
  797. Kind: "Kubernetes",
  798. Name: "kubernetes-backend",
  799. Namespace: referencedConfigNamespace,
  800. },
  801. },
  802. },
  803. }
  804. tlsSecretObject := &corev1.Secret{
  805. ObjectMeta: metav1.ObjectMeta{
  806. Name: "external-secrets-provider-tls",
  807. Namespace: manifestNamespace,
  808. },
  809. Data: tlsSecret,
  810. }
  811. kubeClient := fakeclient.NewClientBuilder().
  812. WithScheme(scheme).
  813. WithObjects(
  814. &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
  815. Name: manifestNamespace,
  816. Labels: map[string]string{
  817. "kubernetes.io/metadata.name": manifestNamespace,
  818. },
  819. }},
  820. &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: referencedConfigNamespace}},
  821. provider,
  822. tlsSecretObject,
  823. ).
  824. Build()
  825. mgr := NewManager(kubeClient, "default", false)
  826. firstClient, err := mgr.Get(context.Background(), esv1.SecretStoreRef{
  827. Name: provider.Name,
  828. Kind: esv1.ProviderKindStr,
  829. }, manifestNamespace, nil)
  830. require.NoError(t, err)
  831. ready, err := firstClient.Validate()
  832. require.NoError(t, err)
  833. assert.Equal(t, esv1.ValidationResultReady, ready)
  834. req := server.LastValidateRequest()
  835. require.NotNil(t, req)
  836. assert.Equal(t, manifestNamespace, req.SourceNamespace)
  837. require.NotNil(t, req.ProviderRef)
  838. assert.Equal(t, "kubernetes-backend", req.ProviderRef.Name)
  839. assert.Equal(t, referencedConfigNamespace, req.ProviderRef.Namespace)
  840. assert.Equal(t, esv1.ProviderKindStr, req.ProviderRef.StoreRefKind)
  841. cachedClient, err := mgr.Get(context.Background(), esv1.SecretStoreRef{
  842. Name: provider.Name,
  843. Kind: esv1.ProviderKindStr,
  844. }, manifestNamespace, nil)
  845. require.NoError(t, err)
  846. assert.Same(t, firstClient, cachedClient)
  847. require.Len(t, mgr.v2PooledConnections, 1)
  848. provider.Generation = 2
  849. require.NoError(t, kubeClient.Update(context.Background(), provider))
  850. secondClient, err := mgr.Get(context.Background(), esv1.SecretStoreRef{
  851. Name: provider.Name,
  852. Kind: esv1.ProviderKindStr,
  853. }, manifestNamespace, nil)
  854. require.NoError(t, err)
  855. assert.NotSame(t, firstClient, secondClient)
  856. ready, err = secondClient.Validate()
  857. require.NoError(t, err)
  858. assert.Equal(t, esv1.ValidationResultReady, ready)
  859. require.Len(t, mgr.v2PooledConnections, 2)
  860. assertPoolMetricEventually(t, registry, "grpc_pool_connections_active", address, true, 1)
  861. assertPoolMetricEventually(t, registry, "grpc_pool_connections_total", address, true, 1)
  862. require.NoError(t, mgr.Close(context.Background()))
  863. assert.Empty(t, mgr.clientMap)
  864. assert.Empty(t, mgr.v2PooledConnections)
  865. assertPoolMetricEventually(t, registry, "grpc_pool_connections_active", address, true, 0)
  866. assertPoolMetricEventually(t, registry, "grpc_pool_connections_idle", address, true, 1)
  867. assertPoolMetricEventually(t, registry, "grpc_pool_connections_total", address, true, 1)
  868. assert.Equal(t, 2, server.ValidateCallCount())
  869. }
  870. func TestGetV2ClusterProviderInvalidatesGenerationCacheAndReleasesPoolReferences(t *testing.T) {
  871. previous := V2ProvidersEnabled()
  872. SetV2ProvidersEnabled(true)
  873. t.Cleanup(func() {
  874. SetV2ProvidersEnabled(previous)
  875. })
  876. registry := installGlobalV2ConnectionPoolForTest(t)
  877. scheme := newManagerTestScheme(t)
  878. server, address, tlsSecret := newRecordingProviderServer(t)
  879. const manifestNamespace = "tenant-a"
  880. const referencedConfigNamespace = "provider-config-ns"
  881. clusterProvider := &esv1.ClusterProvider{
  882. ObjectMeta: metav1.ObjectMeta{
  883. Name: "cluster-provider",
  884. Generation: 1,
  885. },
  886. Spec: esv1.ClusterProviderSpec{
  887. Config: esv1.ProviderConfig{
  888. Address: address,
  889. ProviderRef: esv1.ProviderReference{
  890. APIVersion: "provider.external-secrets.io/v2alpha1",
  891. Kind: "Kubernetes",
  892. Name: "kubernetes-backend",
  893. Namespace: referencedConfigNamespace,
  894. },
  895. },
  896. AuthenticationScope: esv1.AuthenticationScopeProviderNamespace,
  897. Conditions: []esv1.ClusterSecretStoreCondition{
  898. {
  899. Namespaces: []string{manifestNamespace},
  900. },
  901. },
  902. },
  903. }
  904. kubeClient := fakeclient.NewClientBuilder().
  905. WithScheme(scheme).
  906. WithObjects(
  907. &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
  908. Name: manifestNamespace,
  909. Labels: map[string]string{
  910. "kubernetes.io/metadata.name": manifestNamespace,
  911. },
  912. }},
  913. clusterProvider,
  914. &corev1.Secret{
  915. ObjectMeta: metav1.ObjectMeta{
  916. Name: "external-secrets-provider-tls",
  917. Namespace: referencedConfigNamespace,
  918. },
  919. Data: tlsSecret,
  920. },
  921. ).
  922. Build()
  923. mgr := NewManager(kubeClient, "default", false)
  924. firstClient, err := mgr.Get(context.Background(), esv1.SecretStoreRef{
  925. Name: clusterProvider.Name,
  926. Kind: esv1.ClusterProviderKindStr,
  927. }, manifestNamespace, nil)
  928. require.NoError(t, err)
  929. ready, err := firstClient.Validate()
  930. require.NoError(t, err)
  931. assert.Equal(t, esv1.ValidationResultReady, ready)
  932. firstReq := server.LastValidateRequest()
  933. require.NotNil(t, firstReq)
  934. assert.Equal(t, referencedConfigNamespace, firstReq.SourceNamespace)
  935. cachedClient, err := mgr.Get(context.Background(), esv1.SecretStoreRef{
  936. Name: clusterProvider.Name,
  937. Kind: esv1.ClusterProviderKindStr,
  938. }, manifestNamespace, nil)
  939. require.NoError(t, err)
  940. assert.Same(t, firstClient, cachedClient)
  941. require.Len(t, mgr.v2PooledConnections, 1)
  942. clusterProvider.Generation = 2
  943. require.NoError(t, kubeClient.Update(context.Background(), clusterProvider))
  944. secondClient, err := mgr.Get(context.Background(), esv1.SecretStoreRef{
  945. Name: clusterProvider.Name,
  946. Kind: esv1.ClusterProviderKindStr,
  947. }, manifestNamespace, nil)
  948. require.NoError(t, err)
  949. assert.NotSame(t, firstClient, secondClient)
  950. ready, err = secondClient.Validate()
  951. require.NoError(t, err)
  952. assert.Equal(t, esv1.ValidationResultReady, ready)
  953. secondReq := server.LastValidateRequest()
  954. require.NotNil(t, secondReq)
  955. assert.Equal(t, referencedConfigNamespace, secondReq.SourceNamespace)
  956. require.Len(t, mgr.v2PooledConnections, 2)
  957. assertPoolMetricEventually(t, registry, "grpc_pool_connections_active", address, true, 1)
  958. assertPoolMetricEventually(t, registry, "grpc_pool_connections_total", address, true, 1)
  959. require.NoError(t, mgr.Close(context.Background()))
  960. assert.Empty(t, mgr.clientMap)
  961. assert.Empty(t, mgr.v2PooledConnections)
  962. assertPoolMetricEventually(t, registry, "grpc_pool_connections_active", address, true, 0)
  963. assertPoolMetricEventually(t, registry, "grpc_pool_connections_idle", address, true, 1)
  964. assertPoolMetricEventually(t, registry, "grpc_pool_connections_total", address, true, 1)
  965. assert.Equal(t, 2, server.ValidateCallCount())
  966. }
  967. type WrapProvider struct {
  968. newClientFunc func(
  969. context.Context,
  970. esv1.GenericStore,
  971. client.Client,
  972. string) (esv1.SecretsClient, error)
  973. }
  974. // NewClient constructs a SecretsManager Provider.
  975. func (f *WrapProvider) NewClient(
  976. ctx context.Context,
  977. store esv1.GenericStore,
  978. kube client.Client,
  979. namespace string) (esv1.SecretsClient, error) {
  980. return f.newClientFunc(ctx, store, kube, namespace)
  981. }
  982. func (f *WrapProvider) Capabilities() esv1.SecretStoreCapabilities {
  983. return esv1.SecretStoreReadOnly
  984. }
  985. // ValidateStore checks if the provided store is valid.
  986. func (f *WrapProvider) ValidateStore(_ esv1.GenericStore) (admission.Warnings, error) {
  987. return nil, nil
  988. }
  989. type MockFakeClient struct {
  990. id string
  991. closeCalled bool
  992. }
  993. func (c *MockFakeClient) PushSecret(_ context.Context, _ *corev1.Secret, _ esv1.PushSecretData) error {
  994. return nil
  995. }
  996. func (c *MockFakeClient) DeleteSecret(_ context.Context, _ esv1.PushSecretRemoteRef) error {
  997. return nil
  998. }
  999. func (c *MockFakeClient) SecretExists(_ context.Context, _ esv1.PushSecretRemoteRef) (bool, error) {
  1000. return false, nil
  1001. }
  1002. func (c *MockFakeClient) GetSecret(_ context.Context, _ esv1.ExternalSecretDataRemoteRef) ([]byte, error) {
  1003. return nil, nil
  1004. }
  1005. func (c *MockFakeClient) Validate() (esv1.ValidationResult, error) {
  1006. return esv1.ValidationResultReady, nil
  1007. }
  1008. // GetSecretMap returns multiple k/v pairs from the provider.
  1009. func (c *MockFakeClient) GetSecretMap(_ context.Context, _ esv1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  1010. return nil, nil
  1011. }
  1012. // GetAllSecrets returns multiple k/v pairs from the provider.
  1013. func (c *MockFakeClient) GetAllSecrets(_ context.Context, _ esv1.ExternalSecretFind) (map[string][]byte, error) {
  1014. return nil, nil
  1015. }
  1016. func (c *MockFakeClient) Close(_ context.Context) error {
  1017. c.closeCalled = true
  1018. return nil
  1019. }
  1020. func newManagerTestScheme(t *testing.T) *runtime.Scheme {
  1021. t.Helper()
  1022. scheme := runtime.NewScheme()
  1023. utilruntime.Must(clientgoscheme.AddToScheme(scheme))
  1024. utilruntime.Must(apiextensionsv1.AddToScheme(scheme))
  1025. utilruntime.Must(esv1.AddToScheme(scheme))
  1026. return scheme
  1027. }
  1028. func resetGlobalV2ConnectionPoolForTest(t *testing.T) {
  1029. t.Helper()
  1030. if globalV2ConnectionPool != nil {
  1031. _ = globalV2ConnectionPool.Close()
  1032. }
  1033. globalV2ConnectionPool = nil
  1034. globalV2ConnectionPoolOnce = sync.Once{}
  1035. t.Cleanup(func() {
  1036. if globalV2ConnectionPool != nil {
  1037. _ = globalV2ConnectionPool.Close()
  1038. }
  1039. globalV2ConnectionPool = nil
  1040. globalV2ConnectionPoolOnce = sync.Once{}
  1041. })
  1042. }
  1043. func installGlobalV2ConnectionPoolForTest(t *testing.T) *prometheus.Registry {
  1044. t.Helper()
  1045. resetGlobalV2ConnectionPoolForTest(t)
  1046. globalV2ConnectionPool = providergrpc.NewConnectionPool(providergrpc.PoolConfig{
  1047. MaxIdleTime: time.Minute,
  1048. MaxLifetime: time.Minute,
  1049. HealthCheckInterval: 10 * time.Millisecond,
  1050. })
  1051. globalV2ConnectionPoolOnce.Do(func() {})
  1052. registry := prometheus.NewRegistry()
  1053. require.NoError(t, providergrpc.RegisterMetrics(registry))
  1054. return registry
  1055. }
  1056. func assertPoolMetricEventually(t *testing.T, registry *prometheus.Registry, metricName, address string, tlsEnabled bool, want float64) {
  1057. t.Helper()
  1058. labelValue := "false"
  1059. if tlsEnabled {
  1060. labelValue = "true"
  1061. }
  1062. assert.Eventually(t, func() bool {
  1063. got, ok := lookupPoolMetricValue(registry, metricName, address, labelValue)
  1064. return ok && got == want
  1065. }, time.Second, 10*time.Millisecond)
  1066. }
  1067. func lookupPoolMetricValue(registry *prometheus.Registry, metricName, address, tlsEnabled string) (float64, bool) {
  1068. metricFamilies, err := registry.Gather()
  1069. if err != nil {
  1070. return 0, false
  1071. }
  1072. for _, metricFamily := range metricFamilies {
  1073. if metricFamily.GetName() != metricName {
  1074. continue
  1075. }
  1076. for _, metric := range metricFamily.GetMetric() {
  1077. if metricLabelValue(metric.GetLabel(), "address") != address {
  1078. continue
  1079. }
  1080. if metricLabelValue(metric.GetLabel(), "tls_enabled") != tlsEnabled {
  1081. continue
  1082. }
  1083. if gauge := metric.GetGauge(); gauge != nil {
  1084. return gauge.GetValue(), true
  1085. }
  1086. }
  1087. }
  1088. return 0, false
  1089. }
  1090. func metricLabelValue(labels []*dto.LabelPair, name string) string {
  1091. for _, label := range labels {
  1092. if label.GetName() == name {
  1093. return label.GetValue()
  1094. }
  1095. }
  1096. return ""
  1097. }
  1098. type recordingProviderServer struct {
  1099. pb.UnimplementedSecretStoreProviderServer
  1100. mu sync.Mutex
  1101. validateRequests []*pb.ValidateRequest
  1102. }
  1103. func newRecordingProviderServer(t *testing.T) (*recordingProviderServer, string, map[string][]byte) {
  1104. t.Helper()
  1105. serverCert, serverKey, clientCert, clientKey, caCert := newMutualTLSArtifacts(t, "127.0.0.1")
  1106. caPool := x509.NewCertPool()
  1107. require.True(t, caPool.AppendCertsFromPEM(caCert))
  1108. tlsCert, err := tls.X509KeyPair(serverCert, serverKey)
  1109. require.NoError(t, err)
  1110. lis, err := net.Listen("tcp", "127.0.0.1:0")
  1111. require.NoError(t, err)
  1112. recorder := &recordingProviderServer{}
  1113. grpcServer := grpc.NewServer(grpc.Creds(credentials.NewTLS(&tls.Config{
  1114. MinVersion: tls.VersionTLS12,
  1115. Certificates: []tls.Certificate{tlsCert},
  1116. ClientCAs: caPool,
  1117. ClientAuth: tls.RequireAndVerifyClientCert,
  1118. })))
  1119. pb.RegisterSecretStoreProviderServer(grpcServer, recorder)
  1120. go func() {
  1121. _ = grpcServer.Serve(lis)
  1122. }()
  1123. t.Cleanup(func() {
  1124. grpcServer.Stop()
  1125. _ = lis.Close()
  1126. })
  1127. return recorder, lis.Addr().String(), map[string][]byte{
  1128. "ca.crt": caCert,
  1129. "client.crt": clientCert,
  1130. "client.key": clientKey,
  1131. }
  1132. }
  1133. func (s *recordingProviderServer) Validate(_ context.Context, req *pb.ValidateRequest) (*pb.ValidateResponse, error) {
  1134. s.mu.Lock()
  1135. defer s.mu.Unlock()
  1136. s.validateRequests = append(s.validateRequests, req)
  1137. return &pb.ValidateResponse{Valid: true}, nil
  1138. }
  1139. func (s *recordingProviderServer) LastValidateRequest() *pb.ValidateRequest {
  1140. s.mu.Lock()
  1141. defer s.mu.Unlock()
  1142. if len(s.validateRequests) == 0 {
  1143. return nil
  1144. }
  1145. return s.validateRequests[len(s.validateRequests)-1]
  1146. }
  1147. func (s *recordingProviderServer) ValidateCallCount() int {
  1148. s.mu.Lock()
  1149. defer s.mu.Unlock()
  1150. return len(s.validateRequests)
  1151. }
  1152. func newMutualTLSArtifacts(t *testing.T, host string) (serverCertPEM, serverKeyPEM, clientCertPEM, clientKeyPEM, caCertPEM []byte) {
  1153. t.Helper()
  1154. caKey, err := rsa.GenerateKey(rand.Reader, 2048)
  1155. require.NoError(t, err)
  1156. caTemplate := &x509.Certificate{
  1157. SerialNumber: big.NewInt(1),
  1158. Subject: pkix.Name{
  1159. CommonName: "clientmanager-test-ca",
  1160. },
  1161. NotBefore: time.Now().Add(-time.Hour),
  1162. NotAfter: time.Now().Add(24 * time.Hour),
  1163. KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
  1164. BasicConstraintsValid: true,
  1165. IsCA: true,
  1166. }
  1167. caDER, err := x509.CreateCertificate(rand.Reader, caTemplate, caTemplate, &caKey.PublicKey, caKey)
  1168. require.NoError(t, err)
  1169. caCert, err := x509.ParseCertificate(caDER)
  1170. require.NoError(t, err)
  1171. serverCertPEM, serverKeyPEM = newSignedCertificateForTest(t, caCert, caKey, 2, host, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth})
  1172. clientCertPEM, clientKeyPEM = newSignedCertificateForTest(t, caCert, caKey, 3, "client", []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth})
  1173. caCertPEM = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: caDER})
  1174. return serverCertPEM, serverKeyPEM, clientCertPEM, clientKeyPEM, caCertPEM
  1175. }
  1176. func newSignedCertificateForTest(t *testing.T, caCert *x509.Certificate, caKey *rsa.PrivateKey, serial int64, host string, usages []x509.ExtKeyUsage) ([]byte, []byte) {
  1177. t.Helper()
  1178. key, err := rsa.GenerateKey(rand.Reader, 2048)
  1179. require.NoError(t, err)
  1180. template := &x509.Certificate{
  1181. SerialNumber: big.NewInt(serial),
  1182. Subject: pkix.Name{
  1183. CommonName: host,
  1184. },
  1185. NotBefore: time.Now().Add(-time.Hour),
  1186. NotAfter: time.Now().Add(24 * time.Hour),
  1187. KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
  1188. ExtKeyUsage: usages,
  1189. }
  1190. if ip := net.ParseIP(host); ip != nil {
  1191. template.IPAddresses = []net.IP{ip}
  1192. } else {
  1193. template.DNSNames = []string{host}
  1194. }
  1195. der, err := x509.CreateCertificate(rand.Reader, template, caCert, &key.PublicKey, caKey)
  1196. require.NoError(t, err)
  1197. certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der})
  1198. keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
  1199. return certPEM, keyPEM
  1200. }