manager_test.go 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386
  1. /*
  2. Copyright © 2025 ESO Maintainer Team
  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. var once sync.Once
  1052. once.Do(func() {})
  1053. globalV2ConnectionPoolOnce = once
  1054. registry := prometheus.NewRegistry()
  1055. require.NoError(t, providergrpc.RegisterMetrics(registry))
  1056. return registry
  1057. }
  1058. func assertPoolMetricEventually(t *testing.T, registry *prometheus.Registry, metricName, address string, tlsEnabled bool, want float64) {
  1059. t.Helper()
  1060. labelValue := "false"
  1061. if tlsEnabled {
  1062. labelValue = "true"
  1063. }
  1064. assert.Eventually(t, func() bool {
  1065. got, ok := lookupPoolMetricValue(registry, metricName, address, labelValue)
  1066. return ok && got == want
  1067. }, time.Second, 10*time.Millisecond)
  1068. }
  1069. func lookupPoolMetricValue(registry *prometheus.Registry, metricName, address, tlsEnabled string) (float64, bool) {
  1070. metricFamilies, err := registry.Gather()
  1071. if err != nil {
  1072. return 0, false
  1073. }
  1074. for _, metricFamily := range metricFamilies {
  1075. if metricFamily.GetName() != metricName {
  1076. continue
  1077. }
  1078. for _, metric := range metricFamily.GetMetric() {
  1079. if metricLabelValue(metric.GetLabel(), "address") != address {
  1080. continue
  1081. }
  1082. if metricLabelValue(metric.GetLabel(), "tls_enabled") != tlsEnabled {
  1083. continue
  1084. }
  1085. if gauge := metric.GetGauge(); gauge != nil {
  1086. return gauge.GetValue(), true
  1087. }
  1088. }
  1089. }
  1090. return 0, false
  1091. }
  1092. func metricLabelValue(labels []*dto.LabelPair, name string) string {
  1093. for _, label := range labels {
  1094. if label.GetName() == name {
  1095. return label.GetValue()
  1096. }
  1097. }
  1098. return ""
  1099. }
  1100. type recordingProviderServer struct {
  1101. pb.UnimplementedSecretStoreProviderServer
  1102. mu sync.Mutex
  1103. validateRequests []*pb.ValidateRequest
  1104. }
  1105. func newRecordingProviderServer(t *testing.T) (*recordingProviderServer, string, map[string][]byte) {
  1106. t.Helper()
  1107. serverCert, serverKey, clientCert, clientKey, caCert := newMutualTLSArtifacts(t, "127.0.0.1")
  1108. caPool := x509.NewCertPool()
  1109. require.True(t, caPool.AppendCertsFromPEM(caCert))
  1110. tlsCert, err := tls.X509KeyPair(serverCert, serverKey)
  1111. require.NoError(t, err)
  1112. lis, err := net.Listen("tcp", "127.0.0.1:0")
  1113. require.NoError(t, err)
  1114. recorder := &recordingProviderServer{}
  1115. grpcServer := grpc.NewServer(grpc.Creds(credentials.NewTLS(&tls.Config{
  1116. MinVersion: tls.VersionTLS12,
  1117. Certificates: []tls.Certificate{tlsCert},
  1118. ClientCAs: caPool,
  1119. ClientAuth: tls.RequireAndVerifyClientCert,
  1120. })))
  1121. pb.RegisterSecretStoreProviderServer(grpcServer, recorder)
  1122. go func() {
  1123. _ = grpcServer.Serve(lis)
  1124. }()
  1125. t.Cleanup(func() {
  1126. grpcServer.Stop()
  1127. _ = lis.Close()
  1128. })
  1129. return recorder, lis.Addr().String(), map[string][]byte{
  1130. "ca.crt": caCert,
  1131. "client.crt": clientCert,
  1132. "client.key": clientKey,
  1133. }
  1134. }
  1135. func (s *recordingProviderServer) Validate(_ context.Context, req *pb.ValidateRequest) (*pb.ValidateResponse, error) {
  1136. s.mu.Lock()
  1137. defer s.mu.Unlock()
  1138. s.validateRequests = append(s.validateRequests, req)
  1139. return &pb.ValidateResponse{Valid: true}, nil
  1140. }
  1141. func (s *recordingProviderServer) LastValidateRequest() *pb.ValidateRequest {
  1142. s.mu.Lock()
  1143. defer s.mu.Unlock()
  1144. if len(s.validateRequests) == 0 {
  1145. return nil
  1146. }
  1147. return s.validateRequests[len(s.validateRequests)-1]
  1148. }
  1149. func (s *recordingProviderServer) ValidateCallCount() int {
  1150. s.mu.Lock()
  1151. defer s.mu.Unlock()
  1152. return len(s.validateRequests)
  1153. }
  1154. func newMutualTLSArtifacts(t *testing.T, host string) (serverCertPEM, serverKeyPEM, clientCertPEM, clientKeyPEM, caCertPEM []byte) {
  1155. t.Helper()
  1156. caKey, err := rsa.GenerateKey(rand.Reader, 2048)
  1157. require.NoError(t, err)
  1158. caTemplate := &x509.Certificate{
  1159. SerialNumber: big.NewInt(1),
  1160. Subject: pkix.Name{
  1161. CommonName: "clientmanager-test-ca",
  1162. },
  1163. NotBefore: time.Now().Add(-time.Hour),
  1164. NotAfter: time.Now().Add(24 * time.Hour),
  1165. KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
  1166. BasicConstraintsValid: true,
  1167. IsCA: true,
  1168. }
  1169. caDER, err := x509.CreateCertificate(rand.Reader, caTemplate, caTemplate, &caKey.PublicKey, caKey)
  1170. require.NoError(t, err)
  1171. caCert, err := x509.ParseCertificate(caDER)
  1172. require.NoError(t, err)
  1173. serverCertPEM, serverKeyPEM = newSignedCertificateForTest(t, caCert, caKey, 2, host, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth})
  1174. clientCertPEM, clientKeyPEM = newSignedCertificateForTest(t, caCert, caKey, 3, "client", []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth})
  1175. caCertPEM = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: caDER})
  1176. return serverCertPEM, serverKeyPEM, clientCertPEM, clientKeyPEM, caCertPEM
  1177. }
  1178. func newSignedCertificateForTest(t *testing.T, caCert *x509.Certificate, caKey *rsa.PrivateKey, serial int64, host string, usages []x509.ExtKeyUsage) ([]byte, []byte) {
  1179. t.Helper()
  1180. key, err := rsa.GenerateKey(rand.Reader, 2048)
  1181. require.NoError(t, err)
  1182. template := &x509.Certificate{
  1183. SerialNumber: big.NewInt(serial),
  1184. Subject: pkix.Name{
  1185. CommonName: host,
  1186. },
  1187. NotBefore: time.Now().Add(-time.Hour),
  1188. NotAfter: time.Now().Add(24 * time.Hour),
  1189. KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
  1190. ExtKeyUsage: usages,
  1191. }
  1192. if ip := net.ParseIP(host); ip != nil {
  1193. template.IPAddresses = []net.IP{ip}
  1194. } else {
  1195. template.DNSNames = []string{host}
  1196. }
  1197. der, err := x509.CreateCertificate(rand.Reader, template, caCert, &key.PublicKey, caKey)
  1198. require.NoError(t, err)
  1199. certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der})
  1200. keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
  1201. return certPEM, keyPEM
  1202. }