pushsecret_controller_v2_test.go 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309
  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 pushsecret
  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. "testing"
  25. "time"
  26. "github.com/go-logr/logr"
  27. "google.golang.org/grpc"
  28. "google.golang.org/grpc/credentials"
  29. corev1 "k8s.io/api/core/v1"
  30. apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
  31. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  32. "k8s.io/apimachinery/pkg/runtime"
  33. utilruntime "k8s.io/apimachinery/pkg/util/runtime"
  34. clientgoscheme "k8s.io/client-go/kubernetes/scheme"
  35. fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
  36. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  37. esapi "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
  38. pb "github.com/external-secrets/external-secrets/proto/provider"
  39. "github.com/external-secrets/external-secrets/runtime/clientmanager"
  40. )
  41. type pushsecretRecordingProviderServer struct {
  42. pb.UnimplementedSecretStoreProviderServer
  43. pushRequest *pb.PushSecretRequest
  44. deleteRequest *pb.DeleteSecretRequest
  45. }
  46. func (s *pushsecretRecordingProviderServer) PushSecret(_ context.Context, req *pb.PushSecretRequest) (*pb.PushSecretResponse, error) {
  47. s.pushRequest = req
  48. return &pb.PushSecretResponse{}, nil
  49. }
  50. func (s *pushsecretRecordingProviderServer) DeleteSecret(_ context.Context, req *pb.DeleteSecretRequest) (*pb.DeleteSecretResponse, error) {
  51. s.deleteRequest = req
  52. return &pb.DeleteSecretResponse{}, nil
  53. }
  54. func (s *pushsecretRecordingProviderServer) SecretExists(_ context.Context, _ *pb.SecretExistsRequest) (*pb.SecretExistsResponse, error) {
  55. return &pb.SecretExistsResponse{Exists: false}, nil
  56. }
  57. func TestResolvedStoreInfoSupportsProviderKinds(t *testing.T) {
  58. providerInfo, ok := resolvedStoreInfo(esapi.PushSecretStoreRef{
  59. Name: "provider",
  60. Kind: esv1.ProviderKindStr,
  61. }, &esv1.Provider{
  62. ObjectMeta: metav1.ObjectMeta{
  63. Name: "provider",
  64. Labels: map[string]string{"team": "a"},
  65. },
  66. })
  67. if !ok {
  68. t.Fatal("expected provider store info to resolve")
  69. }
  70. if providerInfo.Name != "provider" || providerInfo.Kind != esv1.ProviderKindStr || providerInfo.Labels["team"] != "a" {
  71. t.Fatalf("unexpected provider info: %#v", providerInfo)
  72. }
  73. clusterProviderInfo, ok := resolvedStoreInfo(esapi.PushSecretStoreRef{
  74. Name: "cluster-provider",
  75. Kind: esv1.ClusterProviderKindStr,
  76. }, &esv1.ClusterProvider{
  77. ObjectMeta: metav1.ObjectMeta{
  78. Name: "cluster-provider",
  79. Labels: map[string]string{"scope": "cluster"},
  80. },
  81. })
  82. if !ok {
  83. t.Fatal("expected cluster provider store info to resolve")
  84. }
  85. if clusterProviderInfo.Name != "cluster-provider" || clusterProviderInfo.Kind != esv1.ClusterProviderKindStr || clusterProviderInfo.Labels["scope"] != "cluster" {
  86. t.Fatalf("unexpected cluster provider info: %#v", clusterProviderInfo)
  87. }
  88. }
  89. func TestResolvedStoreInfoInfersOmittedProviderKinds(t *testing.T) {
  90. providerInfo, ok := resolvedStoreInfo(esapi.PushSecretStoreRef{
  91. Name: "provider",
  92. }, &esv1.Provider{
  93. ObjectMeta: metav1.ObjectMeta{
  94. Name: "provider",
  95. Labels: map[string]string{"team": "a"},
  96. },
  97. })
  98. if !ok {
  99. t.Fatal("expected provider store info to resolve")
  100. }
  101. if providerInfo.Kind != esv1.ProviderKindStr {
  102. t.Fatalf("expected kind %q, got %#v", esv1.ProviderKindStr, providerInfo)
  103. }
  104. clusterProviderInfo, ok := resolvedStoreInfo(esapi.PushSecretStoreRef{
  105. Name: "cluster-provider",
  106. }, &esv1.ClusterProvider{
  107. ObjectMeta: metav1.ObjectMeta{
  108. Name: "cluster-provider",
  109. Labels: map[string]string{"scope": "cluster"},
  110. },
  111. })
  112. if !ok {
  113. t.Fatal("expected cluster provider store info to resolve")
  114. }
  115. if clusterProviderInfo.Kind != esv1.ClusterProviderKindStr {
  116. t.Fatalf("expected kind %q, got %#v", esv1.ClusterProviderKindStr, clusterProviderInfo)
  117. }
  118. }
  119. func TestValidateDataToMatchesResolvedStoresSupportsProviderKinds(t *testing.T) {
  120. err := validateDataToMatchesResolvedStores([]esapi.PushSecretDataTo{
  121. {
  122. StoreRef: &esapi.PushSecretStoreRef{
  123. Kind: esv1.ProviderKindStr,
  124. LabelSelector: &metav1.LabelSelector{
  125. MatchLabels: map[string]string{"team": "a"},
  126. },
  127. },
  128. RemoteKey: "bundle",
  129. },
  130. }, []storeInfo{
  131. {Name: "provider", Kind: esv1.ProviderKindStr, Labels: map[string]string{"team": "a"}},
  132. })
  133. if err != nil {
  134. t.Fatalf("expected provider label selector to match, got %v", err)
  135. }
  136. err = validateDataToMatchesResolvedStores([]esapi.PushSecretDataTo{
  137. {
  138. StoreRef: &esapi.PushSecretStoreRef{
  139. Kind: esv1.ClusterProviderKindStr,
  140. LabelSelector: &metav1.LabelSelector{
  141. MatchLabels: map[string]string{"scope": "missing"},
  142. },
  143. },
  144. RemoteKey: "bundle",
  145. },
  146. }, []storeInfo{
  147. {Name: "cluster-provider", Kind: esv1.ClusterProviderKindStr, Labels: map[string]string{"scope": "cluster"}},
  148. })
  149. if err == nil || err.Error() != "dataTo[0]: labelSelector does not match any store in secretStoreRefs" {
  150. t.Fatalf("unexpected error: %v", err)
  151. }
  152. }
  153. func TestPushSecretToProvidersV2UsesProviderPath(t *testing.T) {
  154. previous := clientmanager.V2ProvidersEnabled()
  155. clientmanager.SetV2ProvidersEnabled(true)
  156. t.Cleanup(func() {
  157. clientmanager.SetV2ProvidersEnabled(previous)
  158. })
  159. scheme := newPushSecretTestScheme(t)
  160. server, address, tlsSecret := newPushSecretProviderServer(t)
  161. provider := &esv1.Provider{
  162. ObjectMeta: metav1.ObjectMeta{
  163. Name: "provider",
  164. Namespace: "tenant-a",
  165. Labels: map[string]string{"team": "a"},
  166. },
  167. Spec: esv1.ProviderSpec{
  168. Config: esv1.ProviderConfig{
  169. Address: address,
  170. ProviderRef: esv1.ProviderReference{
  171. APIVersion: "provider.external-secrets.io/v2alpha1",
  172. Kind: "Kubernetes",
  173. Name: "backend",
  174. },
  175. },
  176. },
  177. }
  178. kubeClient := fakeclient.NewClientBuilder().
  179. WithScheme(scheme).
  180. WithObjects(provider, &corev1.Secret{
  181. ObjectMeta: metav1.ObjectMeta{
  182. Name: "external-secrets-provider-tls",
  183. Namespace: "tenant-a",
  184. },
  185. Data: tlsSecret,
  186. }).
  187. Build()
  188. r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
  189. mgr := clientmanager.NewManager(kubeClient, "", false)
  190. defer func() {
  191. _ = mgr.Close(context.Background())
  192. }()
  193. ps := esapi.PushSecret{
  194. ObjectMeta: metav1.ObjectMeta{
  195. Name: "pushsecret",
  196. Namespace: "tenant-a",
  197. },
  198. Spec: esapi.PushSecretSpec{
  199. SecretStoreRefs: []esapi.PushSecretStoreRef{{
  200. Name: "provider",
  201. Kind: esv1.ProviderKindStr,
  202. }},
  203. Data: []esapi.PushSecretData{{
  204. Match: esapi.PushSecretMatch{
  205. SecretKey: "token",
  206. RemoteRef: esapi.PushSecretRemoteRef{
  207. RemoteKey: "remote/path",
  208. Property: "property",
  209. },
  210. },
  211. Metadata: &apiextensionsv1.JSON{Raw: []byte(`{"owner":"eso"}`)},
  212. }},
  213. },
  214. }
  215. secret := &corev1.Secret{
  216. Data: map[string][]byte{"token": []byte("value")},
  217. }
  218. synced, err := r.PushSecretToProvidersV2(context.Background(), map[esapi.PushSecretStoreRef]interface{}{
  219. {Name: "provider", Kind: esv1.ProviderKindStr}: provider,
  220. }, ps, secret, mgr)
  221. if err != nil {
  222. t.Fatalf("PushSecretToProvidersV2() error = %v", err)
  223. }
  224. if server.pushRequest == nil {
  225. t.Fatal("expected push request to be recorded")
  226. }
  227. if server.pushRequest.SourceNamespace != "tenant-a" {
  228. t.Fatalf("unexpected source namespace: %q", server.pushRequest.SourceNamespace)
  229. }
  230. if server.pushRequest.ProviderRef == nil || server.pushRequest.ProviderRef.Name != "backend" {
  231. t.Fatalf("unexpected provider ref: %#v", server.pushRequest.ProviderRef)
  232. }
  233. if string(server.pushRequest.SecretData["token"]) != "value" {
  234. t.Fatalf("unexpected secret data: %#v", server.pushRequest.SecretData)
  235. }
  236. if server.pushRequest.PushSecretData == nil || server.pushRequest.PushSecretData.RemoteKey != "remote/path" || server.pushRequest.PushSecretData.Property != "property" {
  237. t.Fatalf("unexpected push payload: %#v", server.pushRequest.PushSecretData)
  238. }
  239. if string(server.pushRequest.PushSecretData.Metadata) != `{"owner":"eso"}` {
  240. t.Fatalf("unexpected metadata: %q", string(server.pushRequest.PushSecretData.Metadata))
  241. }
  242. if synced["Provider/provider"]["remote/path/property"].Match.SecretKey != "token" {
  243. t.Fatalf("unexpected synced map: %#v", synced)
  244. }
  245. }
  246. func TestPushSecretToProvidersV2UsesProviderPathWhenKindOmitted(t *testing.T) {
  247. previous := clientmanager.V2ProvidersEnabled()
  248. clientmanager.SetV2ProvidersEnabled(true)
  249. t.Cleanup(func() {
  250. clientmanager.SetV2ProvidersEnabled(previous)
  251. })
  252. scheme := newPushSecretTestScheme(t)
  253. server, address, tlsSecret := newPushSecretProviderServer(t)
  254. provider := &esv1.Provider{
  255. ObjectMeta: metav1.ObjectMeta{
  256. Name: "provider",
  257. Namespace: "tenant-a",
  258. Labels: map[string]string{"team": "a"},
  259. },
  260. Spec: esv1.ProviderSpec{
  261. Config: esv1.ProviderConfig{
  262. Address: address,
  263. ProviderRef: esv1.ProviderReference{
  264. APIVersion: "provider.external-secrets.io/v2alpha1",
  265. Kind: "Kubernetes",
  266. Name: "backend",
  267. },
  268. },
  269. },
  270. }
  271. kubeClient := fakeclient.NewClientBuilder().
  272. WithScheme(scheme).
  273. WithObjects(provider, &corev1.Secret{
  274. ObjectMeta: metav1.ObjectMeta{
  275. Name: "external-secrets-provider-tls",
  276. Namespace: "tenant-a",
  277. },
  278. Data: tlsSecret,
  279. }).
  280. Build()
  281. r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
  282. mgr := clientmanager.NewManager(kubeClient, "", false)
  283. defer func() {
  284. _ = mgr.Close(context.Background())
  285. }()
  286. ps := esapi.PushSecret{
  287. ObjectMeta: metav1.ObjectMeta{
  288. Name: "pushsecret",
  289. Namespace: "tenant-a",
  290. },
  291. Spec: esapi.PushSecretSpec{
  292. SecretStoreRefs: []esapi.PushSecretStoreRef{{
  293. Name: "provider",
  294. }},
  295. Data: []esapi.PushSecretData{{
  296. Match: esapi.PushSecretMatch{
  297. SecretKey: "token",
  298. RemoteRef: esapi.PushSecretRemoteRef{
  299. RemoteKey: "remote/path",
  300. Property: "property",
  301. },
  302. },
  303. Metadata: &apiextensionsv1.JSON{Raw: []byte(`{"owner":"eso"}`)},
  304. }},
  305. },
  306. }
  307. secret := &corev1.Secret{
  308. Data: map[string][]byte{"token": []byte("value")},
  309. }
  310. synced, err := r.PushSecretToProvidersV2(context.Background(), map[esapi.PushSecretStoreRef]interface{}{
  311. {Name: "provider"}: provider,
  312. }, ps, secret, mgr)
  313. if err != nil {
  314. t.Fatalf("PushSecretToProvidersV2() error = %v", err)
  315. }
  316. if server.pushRequest == nil {
  317. t.Fatal("expected push request to be recorded")
  318. }
  319. if synced["Provider/provider"]["remote/path/property"].Match.SecretKey != "token" {
  320. t.Fatalf("unexpected synced map: %#v", synced)
  321. }
  322. }
  323. func TestPushSecretToProvidersV2UsesProviderNamespaceAuthScope(t *testing.T) {
  324. previous := clientmanager.V2ProvidersEnabled()
  325. clientmanager.SetV2ProvidersEnabled(true)
  326. t.Cleanup(func() {
  327. clientmanager.SetV2ProvidersEnabled(previous)
  328. })
  329. scheme := newPushSecretTestScheme(t)
  330. server, address, tlsSecret := newPushSecretProviderServer(t)
  331. const manifestNamespace = "tenant-a"
  332. const providerNamespace = "provider-config-ns"
  333. clusterProvider := &esv1.ClusterProvider{
  334. ObjectMeta: metav1.ObjectMeta{
  335. Name: "cluster-provider",
  336. Labels: map[string]string{"scope": "cluster"},
  337. },
  338. Spec: esv1.ClusterProviderSpec{
  339. Config: esv1.ProviderConfig{
  340. Address: address,
  341. ProviderRef: esv1.ProviderReference{
  342. APIVersion: "provider.external-secrets.io/v2alpha1",
  343. Kind: "Kubernetes",
  344. Name: "backend",
  345. Namespace: providerNamespace,
  346. },
  347. },
  348. AuthenticationScope: esv1.AuthenticationScopeProviderNamespace,
  349. Conditions: []esv1.ClusterSecretStoreCondition{{
  350. Namespaces: []string{manifestNamespace},
  351. }},
  352. },
  353. }
  354. kubeClient := fakeclient.NewClientBuilder().
  355. WithScheme(scheme).
  356. WithObjects(
  357. clusterProvider,
  358. &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
  359. Name: manifestNamespace,
  360. Labels: map[string]string{
  361. "kubernetes.io/metadata.name": manifestNamespace,
  362. },
  363. }},
  364. &corev1.Secret{
  365. ObjectMeta: metav1.ObjectMeta{
  366. Name: "external-secrets-provider-tls",
  367. Namespace: providerNamespace,
  368. },
  369. Data: tlsSecret,
  370. },
  371. ).
  372. Build()
  373. r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
  374. mgr := clientmanager.NewManager(kubeClient, "", false)
  375. defer func() {
  376. _ = mgr.Close(context.Background())
  377. }()
  378. ps := esapi.PushSecret{
  379. ObjectMeta: metav1.ObjectMeta{
  380. Name: "pushsecret",
  381. Namespace: manifestNamespace,
  382. },
  383. Spec: esapi.PushSecretSpec{
  384. SecretStoreRefs: []esapi.PushSecretStoreRef{{
  385. Name: "cluster-provider",
  386. Kind: esv1.ClusterProviderKindStr,
  387. }},
  388. Data: []esapi.PushSecretData{{
  389. Match: esapi.PushSecretMatch{
  390. SecretKey: "token",
  391. RemoteRef: esapi.PushSecretRemoteRef{
  392. RemoteKey: "remote/path",
  393. Property: "property",
  394. },
  395. },
  396. Metadata: &apiextensionsv1.JSON{Raw: []byte(`{"owner":"eso"}`)},
  397. }},
  398. },
  399. }
  400. secret := &corev1.Secret{
  401. Data: map[string][]byte{"token": []byte("value")},
  402. }
  403. synced, err := r.PushSecretToProvidersV2(context.Background(), map[esapi.PushSecretStoreRef]interface{}{
  404. {Name: "cluster-provider", Kind: esv1.ClusterProviderKindStr}: clusterProvider,
  405. }, ps, secret, mgr)
  406. if err != nil {
  407. t.Fatalf("PushSecretToProvidersV2() error = %v", err)
  408. }
  409. if server.pushRequest == nil {
  410. t.Fatal("expected push request to be recorded")
  411. }
  412. if server.pushRequest.SourceNamespace != providerNamespace {
  413. t.Fatalf("unexpected source namespace: %q", server.pushRequest.SourceNamespace)
  414. }
  415. if server.pushRequest.ProviderRef == nil || server.pushRequest.ProviderRef.Name != "backend" || server.pushRequest.ProviderRef.Namespace != providerNamespace {
  416. t.Fatalf("unexpected provider ref: %#v", server.pushRequest.ProviderRef)
  417. }
  418. if synced["ClusterProvider/cluster-provider"]["remote/path/property"].Match.SecretKey != "token" {
  419. t.Fatalf("unexpected synced map: %#v", synced)
  420. }
  421. }
  422. func TestDeleteSecretFromProvidersV2UsesClusterProviderPath(t *testing.T) {
  423. previous := clientmanager.V2ProvidersEnabled()
  424. clientmanager.SetV2ProvidersEnabled(true)
  425. t.Cleanup(func() {
  426. clientmanager.SetV2ProvidersEnabled(previous)
  427. })
  428. scheme := newPushSecretTestScheme(t)
  429. server, address, tlsSecret := newPushSecretProviderServer(t)
  430. clusterProvider := &esv1.ClusterProvider{
  431. ObjectMeta: metav1.ObjectMeta{
  432. Name: "cluster-provider",
  433. Labels: map[string]string{"scope": "cluster"},
  434. },
  435. Spec: esv1.ClusterProviderSpec{
  436. Config: esv1.ProviderConfig{
  437. Address: address,
  438. ProviderRef: esv1.ProviderReference{
  439. APIVersion: "provider.external-secrets.io/v2alpha1",
  440. Kind: "Kubernetes",
  441. Name: "backend",
  442. },
  443. },
  444. AuthenticationScope: esv1.AuthenticationScopeManifestNamespace,
  445. Conditions: []esv1.ClusterSecretStoreCondition{{
  446. Namespaces: []string{"tenant-a"},
  447. }},
  448. },
  449. }
  450. kubeClient := fakeclient.NewClientBuilder().
  451. WithScheme(scheme).
  452. WithObjects(
  453. clusterProvider,
  454. &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
  455. Name: "tenant-a",
  456. Labels: map[string]string{
  457. "kubernetes.io/metadata.name": "tenant-a",
  458. },
  459. }},
  460. &corev1.Secret{
  461. ObjectMeta: metav1.ObjectMeta{
  462. Name: "external-secrets-provider-tls",
  463. Namespace: "tenant-a",
  464. },
  465. Data: tlsSecret,
  466. },
  467. ).
  468. Build()
  469. r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
  470. ps := &esapi.PushSecret{
  471. ObjectMeta: metav1.ObjectMeta{
  472. Name: "pushsecret",
  473. Namespace: "tenant-a",
  474. },
  475. Status: esapi.PushSecretStatus{
  476. SyncedPushSecrets: esapi.SyncedPushSecretsMap{
  477. "ClusterProvider/cluster-provider": {
  478. "remote/path": {
  479. Match: esapi.PushSecretMatch{
  480. SecretKey: "token",
  481. RemoteRef: esapi.PushSecretRemoteRef{
  482. RemoteKey: "remote/path",
  483. Property: "property",
  484. },
  485. },
  486. },
  487. },
  488. },
  489. },
  490. }
  491. result, err := r.DeleteSecretFromProvidersV2(context.Background(), ps, esapi.SyncedPushSecretsMap{}, map[esapi.PushSecretStoreRef]interface{}{
  492. {Name: "cluster-provider", Kind: esv1.ClusterProviderKindStr}: clusterProvider,
  493. })
  494. if err != nil {
  495. t.Fatalf("DeleteSecretFromProvidersV2() error = %v", err)
  496. }
  497. if server.deleteRequest == nil {
  498. t.Fatal("expected delete request to be recorded")
  499. }
  500. if server.deleteRequest.SourceNamespace != "tenant-a" {
  501. t.Fatalf("unexpected source namespace: %q", server.deleteRequest.SourceNamespace)
  502. }
  503. if server.deleteRequest.RemoteRef == nil || server.deleteRequest.RemoteRef.RemoteKey != "remote/path" || server.deleteRequest.RemoteRef.Property != "property" {
  504. t.Fatalf("unexpected delete ref: %#v", server.deleteRequest.RemoteRef)
  505. }
  506. if _, ok := result["ClusterProvider/cluster-provider"]; ok {
  507. t.Fatalf("expected synced state to be cleaned up, got %#v", result)
  508. }
  509. }
  510. func TestDeleteSecretFromProvidersV2UsesClusterProviderPathWhenKindOmitted(t *testing.T) {
  511. previous := clientmanager.V2ProvidersEnabled()
  512. clientmanager.SetV2ProvidersEnabled(true)
  513. t.Cleanup(func() {
  514. clientmanager.SetV2ProvidersEnabled(previous)
  515. })
  516. scheme := newPushSecretTestScheme(t)
  517. server, address, tlsSecret := newPushSecretProviderServer(t)
  518. clusterProvider := &esv1.ClusterProvider{
  519. ObjectMeta: metav1.ObjectMeta{
  520. Name: "cluster-provider",
  521. Labels: map[string]string{"scope": "cluster"},
  522. },
  523. Spec: esv1.ClusterProviderSpec{
  524. Config: esv1.ProviderConfig{
  525. Address: address,
  526. ProviderRef: esv1.ProviderReference{
  527. APIVersion: "provider.external-secrets.io/v2alpha1",
  528. Kind: "Kubernetes",
  529. Name: "backend",
  530. },
  531. },
  532. AuthenticationScope: esv1.AuthenticationScopeManifestNamespace,
  533. Conditions: []esv1.ClusterSecretStoreCondition{{
  534. Namespaces: []string{"tenant-a"},
  535. }},
  536. },
  537. }
  538. kubeClient := fakeclient.NewClientBuilder().
  539. WithScheme(scheme).
  540. WithObjects(
  541. clusterProvider,
  542. &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
  543. Name: "tenant-a",
  544. Labels: map[string]string{
  545. "kubernetes.io/metadata.name": "tenant-a",
  546. },
  547. }},
  548. &corev1.Secret{
  549. ObjectMeta: metav1.ObjectMeta{
  550. Name: "external-secrets-provider-tls",
  551. Namespace: "tenant-a",
  552. },
  553. Data: tlsSecret,
  554. },
  555. ).
  556. Build()
  557. r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
  558. ps := &esapi.PushSecret{
  559. ObjectMeta: metav1.ObjectMeta{
  560. Name: "pushsecret",
  561. Namespace: "tenant-a",
  562. },
  563. Status: esapi.PushSecretStatus{
  564. SyncedPushSecrets: esapi.SyncedPushSecretsMap{
  565. "ClusterProvider/cluster-provider": {
  566. "remote/path": {
  567. Match: esapi.PushSecretMatch{
  568. SecretKey: "token",
  569. RemoteRef: esapi.PushSecretRemoteRef{
  570. RemoteKey: "remote/path",
  571. Property: "property",
  572. },
  573. },
  574. },
  575. },
  576. },
  577. },
  578. }
  579. result, err := r.DeleteSecretFromProvidersV2(context.Background(), ps, esapi.SyncedPushSecretsMap{}, map[esapi.PushSecretStoreRef]interface{}{
  580. {Name: "cluster-provider"}: clusterProvider,
  581. })
  582. if err != nil {
  583. t.Fatalf("DeleteSecretFromProvidersV2() error = %v", err)
  584. }
  585. if server.deleteRequest == nil {
  586. t.Fatal("expected delete request to be recorded")
  587. }
  588. if _, ok := result["ClusterProvider/cluster-provider"]; ok {
  589. t.Fatalf("expected synced state to be cleaned up, got %#v", result)
  590. }
  591. }
  592. func TestGetSecretStoresV2ResolvesClusterProviderWhenKindOmitted(t *testing.T) {
  593. previous := clientmanager.V2ProvidersEnabled()
  594. clientmanager.SetV2ProvidersEnabled(true)
  595. t.Cleanup(func() {
  596. clientmanager.SetV2ProvidersEnabled(previous)
  597. })
  598. scheme := newPushSecretTestScheme(t)
  599. clusterProvider := &esv1.ClusterProvider{
  600. ObjectMeta: metav1.ObjectMeta{
  601. Name: "cluster-provider",
  602. },
  603. }
  604. kubeClient := fakeclient.NewClientBuilder().
  605. WithScheme(scheme).
  606. WithObjects(clusterProvider).
  607. Build()
  608. r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
  609. ps := esapi.PushSecret{
  610. ObjectMeta: metav1.ObjectMeta{
  611. Name: "pushsecret",
  612. Namespace: "tenant-a",
  613. },
  614. Spec: esapi.PushSecretSpec{
  615. SecretStoreRefs: []esapi.PushSecretStoreRef{{
  616. Name: "cluster-provider",
  617. }},
  618. },
  619. }
  620. stores, err := r.GetSecretStoresV2(context.Background(), ps)
  621. if err != nil {
  622. t.Fatalf("GetSecretStoresV2() error = %v", err)
  623. }
  624. store, ok := stores[esapi.PushSecretStoreRef{Name: "cluster-provider"}]
  625. if !ok {
  626. t.Fatalf("expected cluster provider store, got %#v", stores)
  627. }
  628. if _, ok := store.(*esv1.ClusterProvider); !ok {
  629. t.Fatalf("expected ClusterProvider, got %T", store)
  630. }
  631. }
  632. func TestGetSecretStoresV2SupportsSecretStoreLabelSelectors(t *testing.T) {
  633. scheme := newPushSecretTestScheme(t)
  634. selectedStore := &esv1.SecretStore{
  635. ObjectMeta: metav1.ObjectMeta{
  636. Name: "selected",
  637. Namespace: "tenant-a",
  638. Labels: map[string]string{"env": "test"},
  639. },
  640. }
  641. otherNamespaceStore := &esv1.SecretStore{
  642. ObjectMeta: metav1.ObjectMeta{
  643. Name: "other-namespace",
  644. Namespace: "tenant-b",
  645. Labels: map[string]string{"env": "test"},
  646. },
  647. }
  648. kubeClient := fakeclient.NewClientBuilder().
  649. WithScheme(scheme).
  650. WithObjects(selectedStore, otherNamespaceStore).
  651. Build()
  652. r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
  653. ps := esapi.PushSecret{
  654. ObjectMeta: metav1.ObjectMeta{
  655. Name: "pushsecret",
  656. Namespace: "tenant-a",
  657. },
  658. Spec: esapi.PushSecretSpec{
  659. SecretStoreRefs: []esapi.PushSecretStoreRef{{
  660. Kind: esv1.SecretStoreKind,
  661. LabelSelector: &metav1.LabelSelector{
  662. MatchLabels: map[string]string{"env": "test"},
  663. },
  664. }},
  665. },
  666. }
  667. stores, err := r.GetSecretStoresV2(context.Background(), ps)
  668. if err != nil {
  669. t.Fatalf("GetSecretStoresV2() error = %v", err)
  670. }
  671. if len(stores) != 1 {
  672. t.Fatalf("expected one resolved store, got %#v", stores)
  673. }
  674. store, ok := stores[esapi.PushSecretStoreRef{Name: "selected", Kind: esv1.SecretStoreKind}]
  675. if !ok {
  676. t.Fatalf("expected selected store, got %#v", stores)
  677. }
  678. if _, ok := store.(*esv1.SecretStore); !ok {
  679. t.Fatalf("expected SecretStore, got %T", store)
  680. }
  681. }
  682. func TestDeleteSecretFromProvidersV2DeletesRemovedStoreEvenWhenNoLongerReferenced(t *testing.T) {
  683. previous := clientmanager.V2ProvidersEnabled()
  684. clientmanager.SetV2ProvidersEnabled(true)
  685. t.Cleanup(func() {
  686. clientmanager.SetV2ProvidersEnabled(previous)
  687. })
  688. scheme := newPushSecretTestScheme(t)
  689. server, address, tlsSecret := newPushSecretProviderServer(t)
  690. clusterProvider := &esv1.ClusterProvider{
  691. ObjectMeta: metav1.ObjectMeta{
  692. Name: "cluster-provider",
  693. },
  694. Spec: esv1.ClusterProviderSpec{
  695. Config: esv1.ProviderConfig{
  696. Address: address,
  697. ProviderRef: esv1.ProviderReference{
  698. APIVersion: "provider.external-secrets.io/v2alpha1",
  699. Kind: "Kubernetes",
  700. Name: "backend",
  701. },
  702. },
  703. AuthenticationScope: esv1.AuthenticationScopeManifestNamespace,
  704. Conditions: []esv1.ClusterSecretStoreCondition{{
  705. Namespaces: []string{"tenant-a"},
  706. }},
  707. },
  708. }
  709. kubeClient := fakeclient.NewClientBuilder().
  710. WithScheme(scheme).
  711. WithObjects(
  712. clusterProvider,
  713. &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
  714. Name: "tenant-a",
  715. Labels: map[string]string{
  716. "kubernetes.io/metadata.name": "tenant-a",
  717. },
  718. }},
  719. &corev1.Secret{
  720. ObjectMeta: metav1.ObjectMeta{
  721. Name: "external-secrets-provider-tls",
  722. Namespace: "tenant-a",
  723. },
  724. Data: tlsSecret,
  725. },
  726. ).
  727. Build()
  728. r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
  729. ps := &esapi.PushSecret{
  730. ObjectMeta: metav1.ObjectMeta{
  731. Name: "pushsecret",
  732. Namespace: "tenant-a",
  733. },
  734. Status: esapi.PushSecretStatus{
  735. SyncedPushSecrets: esapi.SyncedPushSecretsMap{
  736. "ClusterProvider/cluster-provider": {
  737. "remote/path": {
  738. Match: esapi.PushSecretMatch{
  739. SecretKey: "token",
  740. RemoteRef: esapi.PushSecretRemoteRef{
  741. RemoteKey: "remote/path",
  742. Property: "property",
  743. },
  744. },
  745. },
  746. },
  747. },
  748. },
  749. }
  750. result, err := r.DeleteSecretFromProvidersV2(context.Background(), ps, esapi.SyncedPushSecretsMap{}, map[esapi.PushSecretStoreRef]interface{}{})
  751. if err != nil {
  752. t.Fatalf("DeleteSecretFromProvidersV2() error = %v", err)
  753. }
  754. if server.deleteRequest == nil {
  755. t.Fatal("expected delete request to be recorded")
  756. }
  757. if server.deleteRequest.RemoteRef == nil || server.deleteRequest.RemoteRef.RemoteKey != "remote/path" {
  758. t.Fatalf("unexpected delete ref: %#v", server.deleteRequest.RemoteRef)
  759. }
  760. if _, ok := result["ClusterProvider/cluster-provider"]; ok {
  761. t.Fatalf("expected synced state to be cleaned up, got %#v", result)
  762. }
  763. }
  764. func TestDeleteSecretFromProvidersV2UsesProviderNamespaceAuthScope(t *testing.T) {
  765. previous := clientmanager.V2ProvidersEnabled()
  766. clientmanager.SetV2ProvidersEnabled(true)
  767. t.Cleanup(func() {
  768. clientmanager.SetV2ProvidersEnabled(previous)
  769. })
  770. scheme := newPushSecretTestScheme(t)
  771. server, address, tlsSecret := newPushSecretProviderServer(t)
  772. const manifestNamespace = "tenant-a"
  773. const providerNamespace = "provider-config-ns"
  774. clusterProvider := &esv1.ClusterProvider{
  775. ObjectMeta: metav1.ObjectMeta{
  776. Name: "cluster-provider",
  777. Labels: map[string]string{"scope": "cluster"},
  778. },
  779. Spec: esv1.ClusterProviderSpec{
  780. Config: esv1.ProviderConfig{
  781. Address: address,
  782. ProviderRef: esv1.ProviderReference{
  783. APIVersion: "provider.external-secrets.io/v2alpha1",
  784. Kind: "Kubernetes",
  785. Name: "backend",
  786. Namespace: providerNamespace,
  787. },
  788. },
  789. AuthenticationScope: esv1.AuthenticationScopeProviderNamespace,
  790. Conditions: []esv1.ClusterSecretStoreCondition{{
  791. Namespaces: []string{manifestNamespace},
  792. }},
  793. },
  794. }
  795. kubeClient := fakeclient.NewClientBuilder().
  796. WithScheme(scheme).
  797. WithObjects(
  798. clusterProvider,
  799. &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
  800. Name: manifestNamespace,
  801. Labels: map[string]string{
  802. "kubernetes.io/metadata.name": manifestNamespace,
  803. },
  804. }},
  805. &corev1.Secret{
  806. ObjectMeta: metav1.ObjectMeta{
  807. Name: "external-secrets-provider-tls",
  808. Namespace: providerNamespace,
  809. },
  810. Data: tlsSecret,
  811. },
  812. ).
  813. Build()
  814. r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
  815. ps := &esapi.PushSecret{
  816. ObjectMeta: metav1.ObjectMeta{
  817. Name: "pushsecret",
  818. Namespace: manifestNamespace,
  819. },
  820. Status: esapi.PushSecretStatus{
  821. SyncedPushSecrets: esapi.SyncedPushSecretsMap{
  822. "ClusterProvider/cluster-provider": {
  823. "remote/path": {
  824. Match: esapi.PushSecretMatch{
  825. SecretKey: "token",
  826. RemoteRef: esapi.PushSecretRemoteRef{
  827. RemoteKey: "remote/path",
  828. Property: "property",
  829. },
  830. },
  831. },
  832. },
  833. },
  834. },
  835. }
  836. result, err := r.DeleteSecretFromProvidersV2(context.Background(), ps, esapi.SyncedPushSecretsMap{}, map[esapi.PushSecretStoreRef]interface{}{
  837. {Name: "cluster-provider", Kind: esv1.ClusterProviderKindStr}: clusterProvider,
  838. })
  839. if err != nil {
  840. t.Fatalf("DeleteSecretFromProvidersV2() error = %v", err)
  841. }
  842. if server.deleteRequest == nil {
  843. t.Fatal("expected delete request to be recorded")
  844. }
  845. if server.deleteRequest.SourceNamespace != providerNamespace {
  846. t.Fatalf("unexpected source namespace: %q", server.deleteRequest.SourceNamespace)
  847. }
  848. if server.deleteRequest.ProviderRef == nil || server.deleteRequest.ProviderRef.Namespace != providerNamespace {
  849. t.Fatalf("unexpected provider ref: %#v", server.deleteRequest.ProviderRef)
  850. }
  851. if _, ok := result["ClusterProvider/cluster-provider"]; ok {
  852. t.Fatalf("expected synced state to be cleaned up, got %#v", result)
  853. }
  854. }
  855. func TestDeleteSecretFromProvidersV2DeletesOnlyRemovedEntriesForManifestScope(t *testing.T) {
  856. previous := clientmanager.V2ProvidersEnabled()
  857. clientmanager.SetV2ProvidersEnabled(true)
  858. t.Cleanup(func() {
  859. clientmanager.SetV2ProvidersEnabled(previous)
  860. })
  861. scheme := newPushSecretTestScheme(t)
  862. server, address, tlsSecret := newPushSecretProviderServer(t)
  863. clusterProvider := &esv1.ClusterProvider{
  864. ObjectMeta: metav1.ObjectMeta{
  865. Name: "cluster-provider",
  866. },
  867. Spec: esv1.ClusterProviderSpec{
  868. Config: esv1.ProviderConfig{
  869. Address: address,
  870. ProviderRef: esv1.ProviderReference{
  871. APIVersion: "provider.external-secrets.io/v2alpha1",
  872. Kind: "Kubernetes",
  873. Name: "backend",
  874. },
  875. },
  876. AuthenticationScope: esv1.AuthenticationScopeManifestNamespace,
  877. Conditions: []esv1.ClusterSecretStoreCondition{{
  878. Namespaces: []string{"tenant-a"},
  879. }},
  880. },
  881. }
  882. kubeClient := fakeclient.NewClientBuilder().
  883. WithScheme(scheme).
  884. WithObjects(
  885. clusterProvider,
  886. &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
  887. Name: "tenant-a",
  888. Labels: map[string]string{
  889. "kubernetes.io/metadata.name": "tenant-a",
  890. },
  891. }},
  892. &corev1.Secret{
  893. ObjectMeta: metav1.ObjectMeta{
  894. Name: "external-secrets-provider-tls",
  895. Namespace: "tenant-a",
  896. },
  897. Data: tlsSecret,
  898. },
  899. ).
  900. Build()
  901. r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
  902. ps := &esapi.PushSecret{
  903. ObjectMeta: metav1.ObjectMeta{
  904. Name: "pushsecret",
  905. Namespace: "tenant-a",
  906. },
  907. Status: esapi.PushSecretStatus{
  908. SyncedPushSecrets: esapi.SyncedPushSecretsMap{
  909. "ClusterProvider/cluster-provider": {
  910. "remote/keep/property": {
  911. Match: esapi.PushSecretMatch{
  912. SecretKey: "keep",
  913. RemoteRef: esapi.PushSecretRemoteRef{
  914. RemoteKey: "remote/keep",
  915. Property: "property",
  916. },
  917. },
  918. },
  919. "remote/delete/property": {
  920. Match: esapi.PushSecretMatch{
  921. SecretKey: "delete",
  922. RemoteRef: esapi.PushSecretRemoteRef{
  923. RemoteKey: "remote/delete",
  924. Property: "property",
  925. },
  926. },
  927. },
  928. },
  929. },
  930. },
  931. }
  932. newMap := esapi.SyncedPushSecretsMap{
  933. "ClusterProvider/cluster-provider": {
  934. "remote/keep/property": ps.Status.SyncedPushSecrets["ClusterProvider/cluster-provider"]["remote/keep/property"],
  935. },
  936. }
  937. result, err := r.DeleteSecretFromProvidersV2(context.Background(), ps, newMap, map[esapi.PushSecretStoreRef]interface{}{
  938. {Name: "cluster-provider", Kind: esv1.ClusterProviderKindStr}: clusterProvider,
  939. })
  940. if err != nil {
  941. t.Fatalf("DeleteSecretFromProvidersV2() error = %v", err)
  942. }
  943. if server.deleteRequest == nil {
  944. t.Fatal("expected delete request to be recorded")
  945. }
  946. if server.deleteRequest.SourceNamespace != "tenant-a" {
  947. t.Fatalf("unexpected source namespace: %q", server.deleteRequest.SourceNamespace)
  948. }
  949. if server.deleteRequest.RemoteRef == nil || server.deleteRequest.RemoteRef.RemoteKey != "remote/delete" || server.deleteRequest.RemoteRef.Property != "property" {
  950. t.Fatalf("unexpected delete ref: %#v", server.deleteRequest.RemoteRef)
  951. }
  952. storeState, ok := result["ClusterProvider/cluster-provider"]
  953. if !ok {
  954. t.Fatalf("expected synced state for cluster provider, got %#v", result)
  955. }
  956. if len(storeState) != 1 {
  957. t.Fatalf("expected one remaining synced entry, got %#v", storeState)
  958. }
  959. if _, ok := storeState["remote/keep/property"]; !ok {
  960. t.Fatalf("expected keep entry to remain, got %#v", storeState)
  961. }
  962. if _, ok := storeState["remote/delete/property"]; ok {
  963. t.Fatalf("expected delete entry to be removed, got %#v", storeState)
  964. }
  965. }
  966. func TestDeleteSecretFromProvidersV2DeletesOnlyRemovedEntriesForProviderNamespaceScope(t *testing.T) {
  967. previous := clientmanager.V2ProvidersEnabled()
  968. clientmanager.SetV2ProvidersEnabled(true)
  969. t.Cleanup(func() {
  970. clientmanager.SetV2ProvidersEnabled(previous)
  971. })
  972. scheme := newPushSecretTestScheme(t)
  973. server, address, tlsSecret := newPushSecretProviderServer(t)
  974. const manifestNamespace = "tenant-a"
  975. const providerNamespace = "provider-config-ns"
  976. clusterProvider := &esv1.ClusterProvider{
  977. ObjectMeta: metav1.ObjectMeta{
  978. Name: "cluster-provider",
  979. },
  980. Spec: esv1.ClusterProviderSpec{
  981. Config: esv1.ProviderConfig{
  982. Address: address,
  983. ProviderRef: esv1.ProviderReference{
  984. APIVersion: "provider.external-secrets.io/v2alpha1",
  985. Kind: "Kubernetes",
  986. Name: "backend",
  987. Namespace: providerNamespace,
  988. },
  989. },
  990. AuthenticationScope: esv1.AuthenticationScopeProviderNamespace,
  991. Conditions: []esv1.ClusterSecretStoreCondition{{
  992. Namespaces: []string{manifestNamespace},
  993. }},
  994. },
  995. }
  996. kubeClient := fakeclient.NewClientBuilder().
  997. WithScheme(scheme).
  998. WithObjects(
  999. clusterProvider,
  1000. &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
  1001. Name: manifestNamespace,
  1002. Labels: map[string]string{
  1003. "kubernetes.io/metadata.name": manifestNamespace,
  1004. },
  1005. }},
  1006. &corev1.Secret{
  1007. ObjectMeta: metav1.ObjectMeta{
  1008. Name: "external-secrets-provider-tls",
  1009. Namespace: providerNamespace,
  1010. },
  1011. Data: tlsSecret,
  1012. },
  1013. ).
  1014. Build()
  1015. r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
  1016. ps := &esapi.PushSecret{
  1017. ObjectMeta: metav1.ObjectMeta{
  1018. Name: "pushsecret",
  1019. Namespace: manifestNamespace,
  1020. },
  1021. Status: esapi.PushSecretStatus{
  1022. SyncedPushSecrets: esapi.SyncedPushSecretsMap{
  1023. "ClusterProvider/cluster-provider": {
  1024. "remote/keep/property": {
  1025. Match: esapi.PushSecretMatch{
  1026. SecretKey: "keep",
  1027. RemoteRef: esapi.PushSecretRemoteRef{
  1028. RemoteKey: "remote/keep",
  1029. Property: "property",
  1030. },
  1031. },
  1032. },
  1033. "remote/delete/property": {
  1034. Match: esapi.PushSecretMatch{
  1035. SecretKey: "delete",
  1036. RemoteRef: esapi.PushSecretRemoteRef{
  1037. RemoteKey: "remote/delete",
  1038. Property: "property",
  1039. },
  1040. },
  1041. },
  1042. },
  1043. },
  1044. },
  1045. }
  1046. newMap := esapi.SyncedPushSecretsMap{
  1047. "ClusterProvider/cluster-provider": {
  1048. "remote/keep/property": ps.Status.SyncedPushSecrets["ClusterProvider/cluster-provider"]["remote/keep/property"],
  1049. },
  1050. }
  1051. result, err := r.DeleteSecretFromProvidersV2(context.Background(), ps, newMap, map[esapi.PushSecretStoreRef]interface{}{
  1052. {Name: "cluster-provider", Kind: esv1.ClusterProviderKindStr}: clusterProvider,
  1053. })
  1054. if err != nil {
  1055. t.Fatalf("DeleteSecretFromProvidersV2() error = %v", err)
  1056. }
  1057. if server.deleteRequest == nil {
  1058. t.Fatal("expected delete request to be recorded")
  1059. }
  1060. if server.deleteRequest.SourceNamespace != providerNamespace {
  1061. t.Fatalf("unexpected source namespace: %q", server.deleteRequest.SourceNamespace)
  1062. }
  1063. if server.deleteRequest.ProviderRef == nil || server.deleteRequest.ProviderRef.Namespace != providerNamespace {
  1064. t.Fatalf("unexpected provider ref: %#v", server.deleteRequest.ProviderRef)
  1065. }
  1066. if server.deleteRequest.RemoteRef == nil || server.deleteRequest.RemoteRef.RemoteKey != "remote/delete" || server.deleteRequest.RemoteRef.Property != "property" {
  1067. t.Fatalf("unexpected delete ref: %#v", server.deleteRequest.RemoteRef)
  1068. }
  1069. storeState, ok := result["ClusterProvider/cluster-provider"]
  1070. if !ok {
  1071. t.Fatalf("expected synced state for cluster provider, got %#v", result)
  1072. }
  1073. if len(storeState) != 1 {
  1074. t.Fatalf("expected one remaining synced entry, got %#v", storeState)
  1075. }
  1076. if _, ok := storeState["remote/keep/property"]; !ok {
  1077. t.Fatalf("expected keep entry to remain, got %#v", storeState)
  1078. }
  1079. if _, ok := storeState["remote/delete/property"]; ok {
  1080. t.Fatalf("expected delete entry to be removed, got %#v", storeState)
  1081. }
  1082. }
  1083. func newPushSecretTestScheme(t *testing.T) *runtime.Scheme {
  1084. t.Helper()
  1085. scheme := runtime.NewScheme()
  1086. utilruntime.Must(clientgoscheme.AddToScheme(scheme))
  1087. utilruntime.Must(esv1.AddToScheme(scheme))
  1088. utilruntime.Must(esapi.AddToScheme(scheme))
  1089. return scheme
  1090. }
  1091. func newPushSecretProviderServer(t *testing.T) (*pushsecretRecordingProviderServer, string, map[string][]byte) {
  1092. t.Helper()
  1093. serverCert, serverKey, clientCert, clientKey, caCert := newPushSecretTLSArtifacts(t, "127.0.0.1")
  1094. caPool := x509.NewCertPool()
  1095. if !caPool.AppendCertsFromPEM(caCert) {
  1096. t.Fatal("failed to append CA cert")
  1097. }
  1098. tlsCert, err := tls.X509KeyPair(serverCert, serverKey)
  1099. if err != nil {
  1100. t.Fatalf("X509KeyPair() error = %v", err)
  1101. }
  1102. lis, err := net.Listen("tcp", "127.0.0.1:0")
  1103. if err != nil {
  1104. t.Fatalf("Listen() error = %v", err)
  1105. }
  1106. server := &pushsecretRecordingProviderServer{}
  1107. grpcServer := grpc.NewServer(grpc.Creds(credentials.NewTLS(&tls.Config{
  1108. MinVersion: tls.VersionTLS12,
  1109. Certificates: []tls.Certificate{tlsCert},
  1110. ClientCAs: caPool,
  1111. ClientAuth: tls.RequireAndVerifyClientCert,
  1112. })))
  1113. pb.RegisterSecretStoreProviderServer(grpcServer, server)
  1114. go func() {
  1115. _ = grpcServer.Serve(lis)
  1116. }()
  1117. t.Cleanup(func() {
  1118. grpcServer.Stop()
  1119. _ = lis.Close()
  1120. })
  1121. return server, lis.Addr().String(), map[string][]byte{
  1122. "ca.crt": caCert,
  1123. "client.crt": clientCert,
  1124. "client.key": clientKey,
  1125. }
  1126. }
  1127. func newPushSecretTLSArtifacts(t *testing.T, host string) (serverCertPEM, serverKeyPEM, clientCertPEM, clientKeyPEM, caCertPEM []byte) {
  1128. t.Helper()
  1129. caKey, err := rsa.GenerateKey(rand.Reader, 2048)
  1130. if err != nil {
  1131. t.Fatalf("GenerateKey() error = %v", err)
  1132. }
  1133. caTemplate := &x509.Certificate{
  1134. SerialNumber: big.NewInt(1),
  1135. Subject: pkix.Name{
  1136. CommonName: "pushsecret-test-ca",
  1137. },
  1138. NotBefore: time.Now().Add(-time.Hour),
  1139. NotAfter: time.Now().Add(24 * time.Hour),
  1140. KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
  1141. BasicConstraintsValid: true,
  1142. IsCA: true,
  1143. }
  1144. caDER, err := x509.CreateCertificate(rand.Reader, caTemplate, caTemplate, &caKey.PublicKey, caKey)
  1145. if err != nil {
  1146. t.Fatalf("CreateCertificate() error = %v", err)
  1147. }
  1148. caCert, err := x509.ParseCertificate(caDER)
  1149. if err != nil {
  1150. t.Fatalf("ParseCertificate() error = %v", err)
  1151. }
  1152. serverCertPEM, serverKeyPEM = newPushSecretSignedTLSCert(t, caCert, caKey, 2, host, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth})
  1153. clientCertPEM, clientKeyPEM = newPushSecretSignedTLSCert(t, caCert, caKey, 3, host, []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth})
  1154. caCertPEM = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: caDER})
  1155. return serverCertPEM, serverKeyPEM, clientCertPEM, clientKeyPEM, caCertPEM
  1156. }
  1157. func newPushSecretSignedTLSCert(t *testing.T, caCert *x509.Certificate, caKey *rsa.PrivateKey, serial int64, host string, usages []x509.ExtKeyUsage) ([]byte, []byte) {
  1158. t.Helper()
  1159. key, err := rsa.GenerateKey(rand.Reader, 2048)
  1160. if err != nil {
  1161. t.Fatalf("GenerateKey() error = %v", err)
  1162. }
  1163. template := &x509.Certificate{
  1164. SerialNumber: big.NewInt(serial),
  1165. Subject: pkix.Name{
  1166. CommonName: host,
  1167. },
  1168. NotBefore: time.Now().Add(-time.Hour),
  1169. NotAfter: time.Now().Add(24 * time.Hour),
  1170. KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
  1171. ExtKeyUsage: usages,
  1172. }
  1173. if ip := net.ParseIP(host); ip != nil {
  1174. template.IPAddresses = []net.IP{ip}
  1175. } else {
  1176. template.DNSNames = []string{host}
  1177. }
  1178. der, err := x509.CreateCertificate(rand.Reader, template, caCert, &key.PublicKey, caKey)
  1179. if err != nil {
  1180. t.Fatalf("CreateCertificate() error = %v", err)
  1181. }
  1182. return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der}),
  1183. pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
  1184. }