| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879 |
- /*
- Copyright © The ESO Authors
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- https://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package pushsecret
- import (
- "context"
- "crypto/rand"
- "crypto/rsa"
- "crypto/tls"
- "crypto/x509"
- "crypto/x509/pkix"
- "encoding/pem"
- "math/big"
- "net"
- "testing"
- "time"
- "github.com/go-logr/logr"
- "google.golang.org/grpc"
- "google.golang.org/grpc/credentials"
- corev1 "k8s.io/api/core/v1"
- apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime"
- utilruntime "k8s.io/apimachinery/pkg/util/runtime"
- clientgoscheme "k8s.io/client-go/kubernetes/scheme"
- fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
- esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
- esapi "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
- esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
- esv2alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v2alpha1"
- pb "github.com/external-secrets/external-secrets/proto/provider"
- "github.com/external-secrets/external-secrets/runtime/clientmanager"
- )
- type pushsecretRecordingProviderServer struct {
- pb.UnimplementedSecretStoreProviderServer
- pushRequest *pb.PushSecretRequest
- deleteRequest *pb.DeleteSecretRequest
- }
- const (
- pushSecretManifestNamespace = "tenant-a"
- pushSecretRemoteKey = "remote/path"
- pushSecretProperty = "property"
- pushSecretSecretKey = "token"
- )
- func (s *pushsecretRecordingProviderServer) PushSecret(_ context.Context, req *pb.PushSecretRequest) (*pb.PushSecretResponse, error) {
- s.pushRequest = req
- return &pb.PushSecretResponse{}, nil
- }
- func (s *pushsecretRecordingProviderServer) DeleteSecret(_ context.Context, req *pb.DeleteSecretRequest) (*pb.DeleteSecretResponse, error) {
- s.deleteRequest = req
- return &pb.DeleteSecretResponse{}, nil
- }
- func (s *pushsecretRecordingProviderServer) SecretExists(_ context.Context, _ *pb.SecretExistsRequest) (*pb.SecretExistsResponse, error) {
- return &pb.SecretExistsResponse{Exists: false}, nil
- }
- func TestResolvedStoreInfoSupportsCleanStoreKinds(t *testing.T) {
- providerStoreInfo, ok := resolvedStoreInfo(esapi.PushSecretStoreRef{
- Name: "provider-store",
- Kind: esv1.ProviderStoreKindStr,
- }, &esv2alpha1.ProviderStore{
- ObjectMeta: metav1.ObjectMeta{
- Name: "provider-store",
- Labels: map[string]string{"team": "a"},
- },
- })
- if !ok {
- t.Fatal("expected provider store info to resolve")
- }
- if providerStoreInfo.Name != "provider-store" || providerStoreInfo.Kind != esv1.ProviderStoreKindStr || providerStoreInfo.Labels["team"] != "a" {
- t.Fatalf("unexpected provider store info: %#v", providerStoreInfo)
- }
- clusterProviderStoreInfo, ok := resolvedStoreInfo(esapi.PushSecretStoreRef{
- Name: "cluster-provider-store",
- Kind: esv1.ClusterProviderStoreKindStr,
- }, &esv2alpha1.ClusterProviderStore{
- ObjectMeta: metav1.ObjectMeta{
- Name: "cluster-provider-store",
- Labels: map[string]string{"scope": "cluster"},
- },
- })
- if !ok {
- t.Fatal("expected cluster provider store info to resolve")
- }
- if clusterProviderStoreInfo.Name != "cluster-provider-store" || clusterProviderStoreInfo.Kind != esv1.ClusterProviderStoreKindStr || clusterProviderStoreInfo.Labels["scope"] != "cluster" {
- t.Fatalf("unexpected cluster provider store info: %#v", clusterProviderStoreInfo)
- }
- }
- func TestResolvedStoreInfoInfersOmittedCleanStoreKinds(t *testing.T) {
- providerStoreInfo, ok := resolvedStoreInfo(esapi.PushSecretStoreRef{
- Name: "provider-store",
- }, &esv2alpha1.ProviderStore{
- ObjectMeta: metav1.ObjectMeta{
- Name: "provider-store",
- Labels: map[string]string{"team": "a"},
- },
- })
- if !ok {
- t.Fatal("expected provider store info to resolve")
- }
- if providerStoreInfo.Kind != esv1.ProviderStoreKindStr {
- t.Fatalf("expected kind %q, got %#v", esv1.ProviderStoreKindStr, providerStoreInfo)
- }
- clusterProviderStoreInfo, ok := resolvedStoreInfo(esapi.PushSecretStoreRef{
- Name: "cluster-provider-store",
- }, &esv2alpha1.ClusterProviderStore{
- ObjectMeta: metav1.ObjectMeta{
- Name: "cluster-provider-store",
- Labels: map[string]string{"scope": "cluster"},
- },
- })
- if !ok {
- t.Fatal("expected cluster provider store info to resolve")
- }
- if clusterProviderStoreInfo.Kind != esv1.ClusterProviderStoreKindStr {
- t.Fatalf("expected kind %q, got %#v", esv1.ClusterProviderStoreKindStr, clusterProviderStoreInfo)
- }
- }
- func TestValidateDataToMatchesResolvedStoresSupportsCleanStoreKinds(t *testing.T) {
- err := validateDataToMatchesResolvedStores([]esapi.PushSecretDataTo{
- {
- StoreRef: &esapi.PushSecretStoreRef{
- Kind: esv1.ProviderStoreKindStr,
- LabelSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{"team": "a"},
- },
- },
- RemoteKey: "bundle",
- },
- }, []storeInfo{
- {Name: "provider-store", Kind: esv1.ProviderStoreKindStr, Labels: map[string]string{"team": "a"}},
- })
- if err != nil {
- t.Fatalf("expected provider store label selector to match, got %v", err)
- }
- err = validateDataToMatchesResolvedStores([]esapi.PushSecretDataTo{
- {
- StoreRef: &esapi.PushSecretStoreRef{
- Kind: esv1.ClusterProviderStoreKindStr,
- LabelSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{"scope": "missing"},
- },
- },
- RemoteKey: "bundle",
- },
- }, []storeInfo{
- {Name: "cluster-provider-store", Kind: esv1.ClusterProviderStoreKindStr, Labels: map[string]string{"scope": "cluster"}},
- })
- if err == nil || err.Error() != "dataTo[0]: labelSelector does not match any store in secretStoreRefs" {
- t.Fatalf("unexpected error: %v", err)
- }
- }
- func TestPushSecretToProvidersV2UsesProviderStorePath(t *testing.T) {
- scheme := newPushSecretTestScheme(t)
- server, address, tlsSecret := newPushSecretProviderServer(t)
- store := &esv2alpha1.ProviderStore{
- ObjectMeta: metav1.ObjectMeta{
- Name: "aws-prod",
- Namespace: pushSecretManifestNamespace,
- Labels: map[string]string{"team": "a"},
- },
- Spec: esv2alpha1.ProviderStoreSpec{
- RuntimeRef: esv2alpha1.StoreRuntimeRef{Name: "aws"},
- BackendRef: esv2alpha1.BackendObjectReference{
- APIVersion: "provider.aws.external-secrets.io/v2alpha1",
- Kind: "SecretsManager",
- Name: "backend",
- },
- },
- }
- runtimeClass := &esv1alpha1.ClusterProviderClass{
- ObjectMeta: metav1.ObjectMeta{Name: "aws"},
- Spec: esv1alpha1.ClusterProviderClassSpec{Address: address},
- }
- kubeClient := fakeclient.NewClientBuilder().
- WithScheme(scheme).
- WithObjects(
- store,
- runtimeClass,
- &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "external-secrets-provider-tls",
- Namespace: pushSecretManifestNamespace,
- },
- Data: tlsSecret,
- },
- ).
- Build()
- r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
- mgr := clientmanager.NewManager(kubeClient, "", false)
- defer func() {
- _ = mgr.Close(context.Background())
- }()
- ps := esapi.PushSecret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "pushsecret",
- Namespace: "tenant-a",
- },
- Spec: esapi.PushSecretSpec{
- SecretStoreRefs: []esapi.PushSecretStoreRef{{
- Name: store.Name,
- Kind: esv1.ProviderStoreKindStr,
- }},
- Data: []esapi.PushSecretData{{
- Match: esapi.PushSecretMatch{
- SecretKey: pushSecretSecretKey,
- RemoteRef: esapi.PushSecretRemoteRef{
- RemoteKey: pushSecretRemoteKey,
- Property: pushSecretProperty,
- },
- },
- Metadata: &apiextensionsv1.JSON{Raw: []byte(`{"owner":"eso"}`)},
- }},
- },
- }
- secret := &corev1.Secret{
- Data: map[string][]byte{pushSecretSecretKey: []byte("value")},
- }
- synced, err := r.PushSecretToProvidersV2(context.Background(), map[esapi.PushSecretStoreRef]any{
- {Name: store.Name, Kind: esv1.ProviderStoreKindStr}: store,
- }, ps, secret, mgr)
- if err != nil {
- t.Fatalf("PushSecretToProvidersV2() error = %v", err)
- }
- if server.pushRequest == nil {
- t.Fatal("expected push request to be recorded")
- }
- if server.pushRequest.SourceNamespace != pushSecretManifestNamespace {
- t.Fatalf("unexpected source namespace: %q", server.pushRequest.SourceNamespace)
- }
- if server.pushRequest.ProviderRef == nil || server.pushRequest.ProviderRef.Name != "backend" {
- t.Fatalf("unexpected provider ref: %#v", server.pushRequest.ProviderRef)
- }
- if server.pushRequest.ProviderRef.Namespace != pushSecretManifestNamespace || server.pushRequest.ProviderRef.StoreRefKind != esv1.ProviderStoreKindStr {
- t.Fatalf("unexpected provider ref namespace/kind: %#v", server.pushRequest.ProviderRef)
- }
- if string(server.pushRequest.SecretData[pushSecretSecretKey]) != "value" {
- t.Fatalf("unexpected secret data: %#v", server.pushRequest.SecretData)
- }
- if server.pushRequest.PushSecretData == nil || server.pushRequest.PushSecretData.RemoteKey != pushSecretRemoteKey || server.pushRequest.PushSecretData.Property != pushSecretProperty {
- t.Fatalf("unexpected push payload: %#v", server.pushRequest.PushSecretData)
- }
- if string(server.pushRequest.PushSecretData.Metadata) != `{"owner":"eso"}` {
- t.Fatalf("unexpected metadata: %q", string(server.pushRequest.PushSecretData.Metadata))
- }
- if synced["ProviderStore/aws-prod"]["remote/path/property"].Match.SecretKey != pushSecretSecretKey {
- t.Fatalf("unexpected synced map: %#v", synced)
- }
- }
- func TestDeleteSecretFromProvidersV2UsesClusterProviderStorePath(t *testing.T) {
- scheme := newPushSecretTestScheme(t)
- server, address, tlsSecret := newPushSecretProviderServer(t)
- store := &esv2alpha1.ClusterProviderStore{
- ObjectMeta: metav1.ObjectMeta{
- Name: "aws-shared",
- Labels: map[string]string{"scope": "cluster"},
- },
- Spec: esv2alpha1.ClusterProviderStoreSpec{
- RuntimeRef: esv2alpha1.StoreRuntimeRef{Name: "aws"},
- BackendRef: esv2alpha1.BackendObjectReference{
- APIVersion: "provider.aws.external-secrets.io/v2alpha1",
- Kind: "SecretsManager",
- Name: "backend",
- },
- },
- }
- runtimeClass := &esv1alpha1.ClusterProviderClass{
- ObjectMeta: metav1.ObjectMeta{Name: "aws"},
- Spec: esv1alpha1.ClusterProviderClassSpec{Address: address},
- }
- kubeClient := fakeclient.NewClientBuilder().
- WithScheme(scheme).
- WithObjects(
- store,
- runtimeClass,
- &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "external-secrets-provider-tls",
- Namespace: pushSecretManifestNamespace,
- },
- Data: tlsSecret,
- },
- ).
- Build()
- r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
- ps := &esapi.PushSecret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "pushsecret",
- Namespace: "tenant-a",
- },
- Status: esapi.PushSecretStatus{
- SyncedPushSecrets: esapi.SyncedPushSecretsMap{
- "ClusterProviderStore/aws-shared": {
- "remote/path": {
- Match: esapi.PushSecretMatch{
- SecretKey: "token",
- RemoteRef: esapi.PushSecretRemoteRef{
- RemoteKey: "remote/path",
- Property: "property",
- },
- },
- },
- },
- },
- },
- }
- result, err := r.DeleteSecretFromProvidersV2(context.Background(), ps, esapi.SyncedPushSecretsMap{}, map[esapi.PushSecretStoreRef]any{
- {Name: store.Name, Kind: esv1.ClusterProviderStoreKindStr}: store,
- })
- if err != nil {
- t.Fatalf("DeleteSecretFromProvidersV2() error = %v", err)
- }
- if server.deleteRequest == nil {
- t.Fatal("expected delete request to be recorded")
- }
- if server.deleteRequest.SourceNamespace != pushSecretManifestNamespace {
- t.Fatalf("unexpected source namespace: %q", server.deleteRequest.SourceNamespace)
- }
- if server.deleteRequest.ProviderRef == nil ||
- server.deleteRequest.ProviderRef.Namespace != pushSecretManifestNamespace ||
- server.deleteRequest.ProviderRef.StoreRefKind != esv1.ClusterProviderStoreKindStr {
- t.Fatalf("unexpected provider ref: %#v", server.deleteRequest.ProviderRef)
- }
- if server.deleteRequest.RemoteRef == nil || server.deleteRequest.RemoteRef.RemoteKey != pushSecretRemoteKey || server.deleteRequest.RemoteRef.Property != pushSecretProperty {
- t.Fatalf("unexpected delete ref: %#v", server.deleteRequest.RemoteRef)
- }
- if _, ok := result["ClusterProviderStore/aws-shared"]; ok {
- t.Fatalf("expected synced state to be cleaned up, got %#v", result)
- }
- }
- func TestGetSecretStoresV2ResolvesProviderStoreWhenAPIVersionOmitted(t *testing.T) {
- scheme := newPushSecretTestScheme(t)
- store := &esv2alpha1.ProviderStore{
- ObjectMeta: metav1.ObjectMeta{
- Name: "aws-prod",
- Namespace: "tenant-a",
- },
- }
- kubeClient := fakeclient.NewClientBuilder().
- WithScheme(scheme).
- WithObjects(store).
- Build()
- r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
- ps := esapi.PushSecret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "pushsecret",
- Namespace: "tenant-a",
- },
- Spec: esapi.PushSecretSpec{
- SecretStoreRefs: []esapi.PushSecretStoreRef{{
- Name: "aws-prod",
- Kind: esv1.ProviderStoreKindStr,
- }},
- },
- }
- stores, err := r.GetSecretStoresV2(context.Background(), ps)
- if err != nil {
- t.Fatalf("GetSecretStoresV2() error = %v", err)
- }
- if _, ok := stores[ps.Spec.SecretStoreRefs[0]].(*esv2alpha1.ProviderStore); !ok {
- t.Fatalf("expected ProviderStore, got %#v", stores)
- }
- }
- func TestGetSecretStoresV2PrefersProviderStoreWhenKindOmitted(t *testing.T) {
- scheme := newPushSecretTestScheme(t)
- namespacedStore := &esv2alpha1.ProviderStore{
- ObjectMeta: metav1.ObjectMeta{
- Name: "aws-shared",
- Namespace: "tenant-a",
- },
- }
- clusterStore := &esv2alpha1.ClusterProviderStore{
- ObjectMeta: metav1.ObjectMeta{
- Name: "aws-shared",
- },
- }
- kubeClient := fakeclient.NewClientBuilder().
- WithScheme(scheme).
- WithObjects(namespacedStore, clusterStore).
- Build()
- r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
- ps := esapi.PushSecret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "pushsecret",
- Namespace: "tenant-a",
- },
- Spec: esapi.PushSecretSpec{
- SecretStoreRefs: []esapi.PushSecretStoreRef{{
- Name: "aws-shared",
- }},
- },
- }
- stores, err := r.GetSecretStoresV2(context.Background(), ps)
- if err != nil {
- t.Fatalf("GetSecretStoresV2() error = %v", err)
- }
- store, ok := stores[ps.Spec.SecretStoreRefs[0]]
- if !ok {
- t.Fatalf("expected resolved store, got %#v", stores)
- }
- if _, ok := store.(*esv2alpha1.ProviderStore); !ok {
- t.Fatalf("expected ProviderStore to win omitted-kind lookup, got %T", store)
- }
- }
- func TestGetSecretStoresV2ResolvesClusterProviderStoreBySelector(t *testing.T) {
- scheme := newPushSecretTestScheme(t)
- store := &esv2alpha1.ClusterProviderStore{
- ObjectMeta: metav1.ObjectMeta{
- Name: "aws-shared",
- Labels: map[string]string{"team": "shared"},
- },
- }
- otherKindStore := &esv2alpha1.ProviderStore{
- ObjectMeta: metav1.ObjectMeta{
- Name: "aws-tenant",
- Namespace: "tenant-a",
- Labels: map[string]string{"team": "shared"},
- },
- }
- nonMatchingStore := &esv2alpha1.ClusterProviderStore{
- ObjectMeta: metav1.ObjectMeta{
- Name: "aws-other",
- Labels: map[string]string{"team": "other"},
- },
- }
- kubeClient := fakeclient.NewClientBuilder().
- WithScheme(scheme).
- WithObjects(store, otherKindStore, nonMatchingStore).
- Build()
- r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
- ps := esapi.PushSecret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "pushsecret",
- Namespace: "tenant-a",
- },
- Spec: esapi.PushSecretSpec{
- SecretStoreRefs: []esapi.PushSecretStoreRef{{
- Kind: esv1.ClusterProviderStoreKindStr,
- LabelSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{"team": "shared"},
- },
- }},
- },
- }
- stores, err := r.GetSecretStoresV2(context.Background(), ps)
- if err != nil {
- t.Fatalf("GetSecretStoresV2() error = %v", err)
- }
- if len(stores) != 1 {
- t.Fatalf("expected one resolved store, got %d", len(stores))
- }
- selectedStore, ok := stores[esapi.PushSecretStoreRef{Name: "aws-shared", Kind: esv1.ClusterProviderStoreKindStr}]
- if !ok {
- t.Fatalf("expected selected cluster provider store, got %#v", stores)
- }
- if _, ok := selectedStore.(*esv2alpha1.ClusterProviderStore); !ok {
- t.Fatalf("expected ClusterProviderStore, got %T", selectedStore)
- }
- if _, ok := stores[esapi.PushSecretStoreRef{Name: "aws-tenant", Kind: esv1.ProviderStoreKindStr}]; ok {
- t.Fatalf("expected selector to stay within cluster provider store kind, got %#v", stores)
- }
- }
- func TestGetSecretStoresV2SupportsSecretStoreLabelSelectors(t *testing.T) {
- scheme := newPushSecretTestScheme(t)
- selectedStore := &esv1.SecretStore{
- ObjectMeta: metav1.ObjectMeta{
- Name: "selected",
- Namespace: "tenant-a",
- Labels: map[string]string{"env": "test"},
- },
- }
- otherNamespaceStore := &esv1.SecretStore{
- ObjectMeta: metav1.ObjectMeta{
- Name: "other-namespace",
- Namespace: "tenant-b",
- Labels: map[string]string{"env": "test"},
- },
- }
- kubeClient := fakeclient.NewClientBuilder().
- WithScheme(scheme).
- WithObjects(selectedStore, otherNamespaceStore).
- Build()
- r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
- ps := esapi.PushSecret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "pushsecret",
- Namespace: "tenant-a",
- },
- Spec: esapi.PushSecretSpec{
- SecretStoreRefs: []esapi.PushSecretStoreRef{{
- Kind: esv1.SecretStoreKind,
- LabelSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{"env": "test"},
- },
- }},
- },
- }
- stores, err := r.GetSecretStoresV2(context.Background(), ps)
- if err != nil {
- t.Fatalf("GetSecretStoresV2() error = %v", err)
- }
- if len(stores) != 1 {
- t.Fatalf("expected one resolved store, got %#v", stores)
- }
- store, ok := stores[esapi.PushSecretStoreRef{Name: "selected", Kind: esv1.SecretStoreKind}]
- if !ok {
- t.Fatalf("expected selected store, got %#v", stores)
- }
- if _, ok := store.(*esv1.SecretStore); !ok {
- t.Fatalf("expected SecretStore, got %T", store)
- }
- }
- func TestDeleteSecretFromProvidersV2DeletesRemovedStoreEvenWhenNoLongerReferenced(t *testing.T) {
- scheme := newPushSecretTestScheme(t)
- server, address, tlsSecret := newPushSecretProviderServer(t)
- store := &esv2alpha1.ClusterProviderStore{
- ObjectMeta: metav1.ObjectMeta{
- Name: "aws-shared",
- },
- Spec: esv2alpha1.ClusterProviderStoreSpec{
- RuntimeRef: esv2alpha1.StoreRuntimeRef{Name: "aws"},
- BackendRef: esv2alpha1.BackendObjectReference{
- APIVersion: "provider.aws.external-secrets.io/v2alpha1",
- Kind: "SecretsManager",
- Name: "backend",
- },
- },
- }
- runtimeClass := &esv1alpha1.ClusterProviderClass{
- ObjectMeta: metav1.ObjectMeta{Name: "aws"},
- Spec: esv1alpha1.ClusterProviderClassSpec{Address: address},
- }
- kubeClient := fakeclient.NewClientBuilder().
- WithScheme(scheme).
- WithObjects(
- store,
- runtimeClass,
- &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "external-secrets-provider-tls",
- Namespace: pushSecretManifestNamespace,
- },
- Data: tlsSecret,
- },
- ).
- Build()
- r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
- ps := &esapi.PushSecret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "pushsecret",
- Namespace: "tenant-a",
- },
- Status: esapi.PushSecretStatus{
- SyncedPushSecrets: esapi.SyncedPushSecretsMap{
- "ClusterProviderStore/aws-shared": {
- "remote/path": {
- Match: esapi.PushSecretMatch{
- SecretKey: "token",
- RemoteRef: esapi.PushSecretRemoteRef{
- RemoteKey: "remote/path",
- Property: "property",
- },
- },
- },
- },
- },
- },
- }
- result, err := r.DeleteSecretFromProvidersV2(context.Background(), ps, esapi.SyncedPushSecretsMap{}, map[esapi.PushSecretStoreRef]any{})
- if err != nil {
- t.Fatalf("DeleteSecretFromProvidersV2() error = %v", err)
- }
- if server.deleteRequest == nil {
- t.Fatal("expected delete request to be recorded")
- }
- if server.deleteRequest.RemoteRef == nil || server.deleteRequest.RemoteRef.RemoteKey != "remote/path" {
- t.Fatalf("unexpected delete ref: %#v", server.deleteRequest.RemoteRef)
- }
- if _, ok := result["ClusterProviderStore/aws-shared"]; ok {
- t.Fatalf("expected synced state to be cleaned up, got %#v", result)
- }
- }
- func TestDeleteSecretFromProvidersV2DeletesOnlyRemovedEntriesForClusterProviderStore(t *testing.T) {
- scheme := newPushSecretTestScheme(t)
- server, address, tlsSecret := newPushSecretProviderServer(t)
- store := &esv2alpha1.ClusterProviderStore{
- ObjectMeta: metav1.ObjectMeta{
- Name: "aws-shared",
- },
- Spec: esv2alpha1.ClusterProviderStoreSpec{
- RuntimeRef: esv2alpha1.StoreRuntimeRef{Name: "aws"},
- BackendRef: esv2alpha1.BackendObjectReference{
- APIVersion: "provider.aws.external-secrets.io/v2alpha1",
- Kind: "SecretsManager",
- Name: "backend",
- },
- },
- }
- runtimeClass := &esv1alpha1.ClusterProviderClass{
- ObjectMeta: metav1.ObjectMeta{Name: "aws"},
- Spec: esv1alpha1.ClusterProviderClassSpec{Address: address},
- }
- kubeClient := fakeclient.NewClientBuilder().
- WithScheme(scheme).
- WithObjects(
- store,
- runtimeClass,
- &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "external-secrets-provider-tls",
- Namespace: pushSecretManifestNamespace,
- },
- Data: tlsSecret,
- },
- ).
- Build()
- r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
- ps := &esapi.PushSecret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "pushsecret",
- Namespace: "tenant-a",
- },
- Status: esapi.PushSecretStatus{
- SyncedPushSecrets: esapi.SyncedPushSecretsMap{
- "ClusterProviderStore/aws-shared": {
- "remote/keep/property": {
- Match: esapi.PushSecretMatch{
- SecretKey: "keep",
- RemoteRef: esapi.PushSecretRemoteRef{
- RemoteKey: "remote/keep",
- Property: "property",
- },
- },
- },
- "remote/delete/property": {
- Match: esapi.PushSecretMatch{
- SecretKey: "delete",
- RemoteRef: esapi.PushSecretRemoteRef{
- RemoteKey: "remote/delete",
- Property: "property",
- },
- },
- },
- },
- },
- },
- }
- newMap := esapi.SyncedPushSecretsMap{
- "ClusterProviderStore/aws-shared": {
- "remote/keep/property": ps.Status.SyncedPushSecrets["ClusterProviderStore/aws-shared"]["remote/keep/property"],
- },
- }
- result, err := r.DeleteSecretFromProvidersV2(context.Background(), ps, newMap, map[esapi.PushSecretStoreRef]any{
- {Name: store.Name, Kind: esv1.ClusterProviderStoreKindStr}: store,
- })
- if err != nil {
- t.Fatalf("DeleteSecretFromProvidersV2() error = %v", err)
- }
- if server.deleteRequest == nil {
- t.Fatal("expected delete request to be recorded")
- }
- if server.deleteRequest.SourceNamespace != pushSecretManifestNamespace {
- t.Fatalf("unexpected source namespace: %q", server.deleteRequest.SourceNamespace)
- }
- if server.deleteRequest.RemoteRef == nil || server.deleteRequest.RemoteRef.RemoteKey != "remote/delete" || server.deleteRequest.RemoteRef.Property != "property" {
- t.Fatalf("unexpected delete ref: %#v", server.deleteRequest.RemoteRef)
- }
- storeState, ok := result["ClusterProviderStore/aws-shared"]
- if !ok {
- t.Fatalf("expected synced state for cluster provider store, got %#v", result)
- }
- if len(storeState) != 1 {
- t.Fatalf("expected one remaining synced entry, got %#v", storeState)
- }
- if _, ok := storeState["remote/keep/property"]; !ok {
- t.Fatalf("expected keep entry to remain, got %#v", storeState)
- }
- if _, ok := storeState["remote/delete/property"]; ok {
- t.Fatalf("expected delete entry to be removed, got %#v", storeState)
- }
- }
- func newPushSecretTestScheme(t *testing.T) *runtime.Scheme {
- t.Helper()
- scheme := runtime.NewScheme()
- utilruntime.Must(clientgoscheme.AddToScheme(scheme))
- utilruntime.Must(esv1.AddToScheme(scheme))
- utilruntime.Must(esapi.AddToScheme(scheme))
- utilruntime.Must(esv1alpha1.AddToScheme(scheme))
- utilruntime.Must(esv2alpha1.AddToScheme(scheme))
- return scheme
- }
- func newPushSecretProviderServer(t *testing.T) (*pushsecretRecordingProviderServer, string, map[string][]byte) {
- t.Helper()
- serverCert, serverKey, clientCert, clientKey, caCert := newPushSecretTLSArtifacts(t, "127.0.0.1")
- caPool := x509.NewCertPool()
- if !caPool.AppendCertsFromPEM(caCert) {
- t.Fatal("failed to append CA cert")
- }
- tlsCert, err := tls.X509KeyPair(serverCert, serverKey)
- if err != nil {
- t.Fatalf("X509KeyPair() error = %v", err)
- }
- lis, err := net.Listen("tcp", "127.0.0.1:0")
- if err != nil {
- t.Fatalf("Listen() error = %v", err)
- }
- server := &pushsecretRecordingProviderServer{}
- grpcServer := grpc.NewServer(grpc.Creds(credentials.NewTLS(&tls.Config{
- MinVersion: tls.VersionTLS12,
- Certificates: []tls.Certificate{tlsCert},
- ClientCAs: caPool,
- ClientAuth: tls.RequireAndVerifyClientCert,
- })))
- pb.RegisterSecretStoreProviderServer(grpcServer, server)
- go func() {
- _ = grpcServer.Serve(lis)
- }()
- t.Cleanup(func() {
- grpcServer.Stop()
- _ = lis.Close()
- })
- return server, lis.Addr().String(), map[string][]byte{
- "ca.crt": caCert,
- "client.crt": clientCert,
- "client.key": clientKey,
- }
- }
- func newPushSecretTLSArtifacts(t *testing.T, host string) (serverCertPEM, serverKeyPEM, clientCertPEM, clientKeyPEM, caCertPEM []byte) {
- t.Helper()
- caKey, err := rsa.GenerateKey(rand.Reader, 2048)
- if err != nil {
- t.Fatalf("GenerateKey() error = %v", err)
- }
- caTemplate := &x509.Certificate{
- SerialNumber: big.NewInt(1),
- Subject: pkix.Name{
- CommonName: "pushsecret-test-ca",
- },
- NotBefore: time.Now().Add(-time.Hour),
- NotAfter: time.Now().Add(24 * time.Hour),
- KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
- BasicConstraintsValid: true,
- IsCA: true,
- }
- caDER, err := x509.CreateCertificate(rand.Reader, caTemplate, caTemplate, &caKey.PublicKey, caKey)
- if err != nil {
- t.Fatalf("CreateCertificate() error = %v", err)
- }
- caCert, err := x509.ParseCertificate(caDER)
- if err != nil {
- t.Fatalf("ParseCertificate() error = %v", err)
- }
- serverCertPEM, serverKeyPEM = newPushSecretSignedTLSCert(t, caCert, caKey, 2, host, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth})
- clientCertPEM, clientKeyPEM = newPushSecretSignedTLSCert(t, caCert, caKey, 3, host, []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth})
- caCertPEM = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: caDER})
- return serverCertPEM, serverKeyPEM, clientCertPEM, clientKeyPEM, caCertPEM
- }
- func newPushSecretSignedTLSCert(t *testing.T, caCert *x509.Certificate, caKey *rsa.PrivateKey, serial int64, host string, usages []x509.ExtKeyUsage) ([]byte, []byte) {
- t.Helper()
- key, err := rsa.GenerateKey(rand.Reader, 2048)
- if err != nil {
- t.Fatalf("GenerateKey() error = %v", err)
- }
- template := &x509.Certificate{
- SerialNumber: big.NewInt(serial),
- Subject: pkix.Name{
- CommonName: host,
- },
- NotBefore: time.Now().Add(-time.Hour),
- NotAfter: time.Now().Add(24 * time.Hour),
- KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
- ExtKeyUsage: usages,
- }
- if ip := net.ParseIP(host); ip != nil {
- template.IPAddresses = []net.IP{ip}
- } else {
- template.DNSNames = []string{host}
- }
- der, err := x509.CreateCertificate(rand.Reader, template, caCert, &key.PublicKey, caKey)
- if err != nil {
- t.Fatalf("CreateCertificate() error = %v", err)
- }
- return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der}),
- pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
- }
|