Quellcode durchsuchen

Merge branch 'main' into feature/docs-versioning

Gustavo Fernandes de Carvalho vor 4 Jahren
Ursprung
Commit
47a7425a2a
47 geänderte Dateien mit 1944 neuen und 326 gelöschten Zeilen
  1. 0 5
      .github/codecov.yml
  2. 8 10
      .github/workflows/ci.yml
  3. 45 2
      .github/workflows/e2e-managed.yml
  4. 6 4
      .github/workflows/e2e.yml
  5. 2 2
      .github/workflows/helm.yml
  6. 27 0
      apis/externalsecrets/v1alpha1/secretstore_fake_types.go
  7. 4 0
      apis/externalsecrets/v1alpha1/secretstore_types.go
  8. 49 0
      apis/externalsecrets/v1alpha1/zz_generated.deepcopy.go
  9. 23 0
      deploy/crds/external-secrets.io_clustersecretstores.yaml
  10. 23 0
      deploy/crds/external-secrets.io_secretstores.yaml
  11. 76 0
      docs/contributing-process.md
  12. 26 0
      docs/provider-fake.md
  13. 18 0
      docs/snippets/fake-provider-es.yaml
  14. 9 0
      docs/snippets/fake-provider-secret.yaml
  15. 20 0
      docs/snippets/fake-provider-store.yaml
  16. 336 0
      docs/spec.md
  17. 1 1
      e2e/Makefile
  18. 97 0
      e2e/suite/aws/common.go
  19. 45 0
      e2e/suite/aws/parameterstore/parameterstore.go
  20. 85 0
      e2e/suite/aws/parameterstore/parameterstore_managed.go
  21. 165 0
      e2e/suite/aws/parameterstore/provider.go
  22. 14 76
      e2e/suite/aws/secretsmanager/provider.go
  23. 0 0
      e2e/suite/aws/secretsmanager/secretsmanager.go
  24. 85 0
      e2e/suite/aws/secretsmanager/secretsmanager_managed.go
  25. 0 102
      e2e/suite/aws/secretsmanager_managed.go
  26. 66 0
      e2e/suite/azure/azure_cert.go
  27. 69 0
      e2e/suite/azure/azure_key.go
  28. 2 1
      e2e/suite/azure/azure_secret.go
  29. 80 4
      e2e/suite/azure/provider.go
  30. 2 1
      e2e/suite/import.go
  31. 11 18
      go.mod
  32. 27 32
      go.sum
  33. 1 0
      hack/api-docs/mkdocs.yml
  34. 1 3
      pkg/controllers/externalsecret/externalsecret_controller_template.go
  35. 82 1
      pkg/controllers/externalsecret/externalsecret_controller_test.go
  36. 57 0
      pkg/controllers/externalsecret/metrics.go
  37. 7 1
      pkg/controllers/externalsecret/suite_test.go
  38. 51 58
      pkg/provider/fake/fake.go
  39. 194 0
      pkg/provider/fake/fake_test.go
  40. 1 1
      pkg/provider/gcp/secretmanager/fake/fake.go
  41. 1 1
      pkg/provider/gcp/secretmanager/secretsmanager.go
  42. 1 1
      pkg/provider/gcp/secretmanager/secretsmanager_workload_identity.go
  43. 1 1
      pkg/provider/gcp/secretmanager/secretsmanager_workload_identity_test.go
  44. 1 0
      pkg/provider/register/register.go
  45. 103 0
      pkg/provider/testing/fake/fake.go
  46. 3 1
      pkg/provider/webhook/webhook_test.go
  47. 19 0
      terraform/aws/modules/cluster/irsa.tf

+ 0 - 5
.github/codecov.yml

@@ -1,5 +0,0 @@
-ignore:
-- pkg/provider/**/fake
-coverage:
-  round: down
-  precision: 2

+ 8 - 10
.github/workflows/ci.yml

@@ -12,9 +12,7 @@ env:
   # Common versions
   # Common versions
   GO_VERSION: '1.17'
   GO_VERSION: '1.17'
   GOLANGCI_VERSION: 'v1.42.1'
   GOLANGCI_VERSION: 'v1.42.1'
-  # list of available versions: https://storage.googleapis.com/kubebuilder-tools
-  # TODO: 1.21.2 does not shut down properly with controller-runtime 0.9.2
-  KUBEBUILDER_TOOLS_VERSION: '1.20.2'
+  KUBERNETES_VERSION: '1.23.x'
   DOCKER_BUILDX_VERSION: 'v0.4.2'
   DOCKER_BUILDX_VERSION: 'v0.4.2'
 
 
   # Common users. We can't run a step 'if secrets.GHCR_USERNAME != ""' but we can run
   # Common users. We can't run a step 'if secrets.GHCR_USERNAME != ""' but we can run
@@ -164,22 +162,22 @@ jobs:
           key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}
           key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}
           restore-keys: ${{ runner.os }}-pkg-
           restore-keys: ${{ runner.os }}-pkg-
 
 
-      - name: Add envtest binaries
-        run:  |
-          curl -sSLo envtest-bins.tar.gz "https://storage.googleapis.com/kubebuilder-tools/kubebuilder-tools-${{env.KUBEBUILDER_TOOLS_VERSION}}-linux-amd64.tar.gz"
-          sudo mkdir -p /usr/local/kubebuilder
-          sudo tar -C /usr/local/kubebuilder --strip-components=1 -zvxf envtest-bins.tar.gz
+      - name: Add setup-envtest
+        run: |
+          go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest
+          setup-envtest use ${{env.KUBERNETES_VERSION}} -p env --os $(go env GOOS) --arch $(go env GOARCH)
 
 
       - name: Cache envtest binaries
       - name: Cache envtest binaries
         uses: actions/cache@v2.1.7
         uses: actions/cache@v2.1.7
         with:
         with:
-          path: /usr/local/kubebuilder
-          key: ${{ runner.os }}-kubebuilder-${{env.KUBEBUILDER_TOOLS_VERSION}}
+          path: /home/runner/.local/share/kubebuilder-envtest/
+          key: ${{ runner.os }}-kubebuilder-${{env.KUBERNETES_VERSION}}
           restore-keys: ${{ runner.os }}-kubebuilder-
           restore-keys: ${{ runner.os }}-kubebuilder-
 
 
       - name: Run Unit Tests
       - name: Run Unit Tests
         run: |
         run: |
           export KUBEBUILDER_ATTACH_CONTROL_PLANE_OUTPUT=true
           export KUBEBUILDER_ATTACH_CONTROL_PLANE_OUTPUT=true
+          source <(setup-envtest use ${{env.KUBERNETES_VERSION}} -p env --os $(go env GOOS) --arch $(go env GOARCH))
           make test
           make test
 
 
 
 

+ 45 - 2
.github/workflows/e2e-managed.yml

@@ -1,6 +1,5 @@
 # Run secret-dependent e2e tests only after /ok-to-test-managed approval
 # Run secret-dependent e2e tests only after /ok-to-test-managed approval
 on:
 on:
-  pull_request:
   repository_dispatch:
   repository_dispatch:
     types: [ok-to-test-managed-command]
     types: [ok-to-test-managed-command]
 
 
@@ -49,6 +48,48 @@ jobs:
 
 
     steps:
     steps:
 
 
+    # create new status check for this specific provider
+    - uses: actions/github-script@v1
+      if: ${{ always() }}
+      env:
+        number: ${{ github.event.client_payload.pull_request.number }}
+        provider: ${{ github.event.client_payload.slash_command.args.named.provider }}
+        job: ${{ github.job }}
+      with:
+        github-token: ${{ secrets.GITHUB_TOKEN }}
+        script: |
+          const { data: pull } = await github.pulls.get({
+            ...context.repo,
+            pull_number: process.env.number
+          });
+          const ref = pull.head.sha;
+          console.log("\n\nPR sha: " + ref)
+          const { data: checks } = await github.checks.listForRef({
+            ...context.repo,
+            ref
+          });
+          const job_name = process.env.job + "-" + process.env.provider
+          console.log("\n\nPR CHECKS: " + checks)
+          const check = checks.check_runs.filter(c => c.name === job_name);
+          console.log("\n\nPR Filtered CHECK: " + check)
+          console.log(check)
+          if(check && check.length > 0){
+            const { data: result } = await github.checks.update({
+              ...context.repo,
+              check_run_id: check[0].id,
+              status: 'in_progress',
+            });
+            return result;
+          }
+          const { data: result } = await github.checks.create({
+            ...context.repo,
+            name: job_name,
+            head_sha: pull.head.sha,
+            status: 'in_progress',
+          });
+          return result;
+
+
     # Check out merge commit
     # Check out merge commit
     - name: Fork based /ok-to-test-managed checkout
     - name: Fork based /ok-to-test-managed checkout
       uses: actions/checkout@v2
       uses: actions/checkout@v2
@@ -164,6 +205,7 @@ jobs:
       if: ${{ always() }}
       if: ${{ always() }}
       env:
       env:
         number: ${{ github.event.client_payload.pull_request.number }}
         number: ${{ github.event.client_payload.pull_request.number }}
+        provider: ${{ github.event.client_payload.slash_command.args.named.provider }}
         job: ${{ github.job }}
         job: ${{ github.job }}
         # Conveniently, job.status maps to https://developer.github.com/v3/checks/runs/#update-a-check-run
         # Conveniently, job.status maps to https://developer.github.com/v3/checks/runs/#update-a-check-run
         conclusion: ${{ job.status }}
         conclusion: ${{ job.status }}
@@ -180,8 +222,9 @@ jobs:
             ...context.repo,
             ...context.repo,
             ref
             ref
           });
           });
+          const job_name = process.env.job + "-" + process.env.provider
           console.log("\n\nPR CHECKS: " + checks)
           console.log("\n\nPR CHECKS: " + checks)
-          const check = checks.check_runs.filter(c => c.name === process.env.job);
+          const check = checks.check_runs.filter(c => c.name === job_name);
           console.log("\n\nPR Filtered CHECK: " + check)
           console.log("\n\nPR Filtered CHECK: " + check)
           console.log(check)
           console.log(check)
           const { data: result } = await github.checks.update({
           const { data: result } = await github.checks.update({

+ 6 - 4
.github/workflows/e2e.yml

@@ -9,6 +9,8 @@ env:
   GO_VERSION: '1.17'
   GO_VERSION: '1.17'
   GOLANGCI_VERSION: 'v1.33'
   GOLANGCI_VERSION: 'v1.33'
   DOCKER_BUILDX_VERSION: 'v0.4.2'
   DOCKER_BUILDX_VERSION: 'v0.4.2'
+  KIND_VERSION: 'v0.11.1'
+  KIND_IMAGE: 'kindest/node:v1.23.3'
 
 
   # Common users. We can't run a step 'if secrets.GHCR_USERNAME != ""' but we can run
   # Common users. We can't run a step 'if secrets.GHCR_USERNAME != ""' but we can run
   # a step 'if env.GHCR_USERNAME' != ""', so we copy these to succinctly test whether
   # a step 'if env.GHCR_USERNAME' != ""', so we copy these to succinctly test whether
@@ -71,9 +73,9 @@ jobs:
     - name: Setup kind
     - name: Setup kind
       uses: engineerd/setup-kind@v0.5.0
       uses: engineerd/setup-kind@v0.5.0
       with:
       with:
-        version: "v0.11.1"
+        version: ${{env.KIND_VERSION}}
         wait: 10m
         wait: 10m
-        node_image: kindest/node:v1.20.7
+        node_image: ${{env.KIND_IMAGE}}
         name: external-secrets
         name: external-secrets
 
 
     - name: Setup Docker Buildx
     - name: Setup Docker Buildx
@@ -134,9 +136,9 @@ jobs:
     - name: Setup kind
     - name: Setup kind
       uses: engineerd/setup-kind@v0.5.0
       uses: engineerd/setup-kind@v0.5.0
       with:
       with:
-        version: "v0.11.1"
+        version: ${{env.KIND_VERSION}}
         wait: 10m
         wait: 10m
-        node_image: kindest/node:v1.20.7
+        node_image: ${{env.KIND_IMAGE}}
         name: external-secrets
         name: external-secrets
 
 
     - name: Setup Docker Buildx
     - name: Setup Docker Buildx

+ 2 - 2
.github/workflows/helm.yml

@@ -26,7 +26,7 @@ jobs:
           make helm.generate
           make helm.generate
 
 
       - name: Set up Helm
       - name: Set up Helm
-        uses: azure/setup-helm@v1.1
+        uses: azure/setup-helm@v2.0
         with:
         with:
           version: v3.4.2
           version: v3.4.2
 
 
@@ -62,7 +62,7 @@ jobs:
           git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
           git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
 
 
       - name: Set up Helm
       - name: Set up Helm
-        uses: azure/setup-helm@v1.1
+        uses: azure/setup-helm@v2.0
         with:
         with:
           version: v3.4.2
           version: v3.4.2
 
 

+ 27 - 0
apis/externalsecrets/v1alpha1/secretstore_fake_types.go

@@ -0,0 +1,27 @@
+/*
+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
+
+    http://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 v1alpha1
+
+// FakeProvider configures a fake provider that returns static values.
+type FakeProvider struct {
+	Data []FakeProviderData `json:"data"`
+}
+
+type FakeProviderData struct {
+	Key      string            `json:"key"`
+	Value    string            `json:"value,omitempty"`
+	ValueMap map[string]string `json:"valueMap,omitempty"`
+	Version  string            `json:"version,omitempty"`
+}

+ 4 - 0
apis/externalsecrets/v1alpha1/secretstore_types.go

@@ -81,6 +81,10 @@ type SecretStoreProvider struct {
 	// Webhook configures this store to sync secrets using a generic templated webhook
 	// Webhook configures this store to sync secrets using a generic templated webhook
 	// +optional
 	// +optional
 	Webhook *WebhookProvider `json:"webhook,omitempty"`
 	Webhook *WebhookProvider `json:"webhook,omitempty"`
+
+	// Fake configures a store with static key/value pairs
+	// +optional
+	Fake *FakeProvider `json:"fake,omitempty"`
 }
 }
 
 
 type SecretStoreRetrySettings struct {
 type SecretStoreRetrySettings struct {

+ 49 - 0
apis/externalsecrets/v1alpha1/zz_generated.deepcopy.go

@@ -599,6 +599,50 @@ func (in *ExternalSecretTemplateMetadata) DeepCopy() *ExternalSecretTemplateMeta
 	return out
 	return out
 }
 }
 
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *FakeProvider) DeepCopyInto(out *FakeProvider) {
+	*out = *in
+	if in.Data != nil {
+		in, out := &in.Data, &out.Data
+		*out = make([]FakeProviderData, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FakeProvider.
+func (in *FakeProvider) DeepCopy() *FakeProvider {
+	if in == nil {
+		return nil
+	}
+	out := new(FakeProvider)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *FakeProviderData) DeepCopyInto(out *FakeProviderData) {
+	*out = *in
+	if in.ValueMap != nil {
+		in, out := &in.ValueMap, &out.ValueMap
+		*out = make(map[string]string, len(*in))
+		for key, val := range *in {
+			(*out)[key] = val
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FakeProviderData.
+func (in *FakeProviderData) DeepCopy() *FakeProviderData {
+	if in == nil {
+		return nil
+	}
+	out := new(FakeProviderData)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *GCPSMAuth) DeepCopyInto(out *GCPSMAuth) {
 func (in *GCPSMAuth) DeepCopyInto(out *GCPSMAuth) {
 	*out = *in
 	*out = *in
@@ -939,6 +983,11 @@ func (in *SecretStoreProvider) DeepCopyInto(out *SecretStoreProvider) {
 		*out = new(WebhookProvider)
 		*out = new(WebhookProvider)
 		(*in).DeepCopyInto(*out)
 		(*in).DeepCopyInto(*out)
 	}
 	}
+	if in.Fake != nil {
+		in, out := &in.Fake, &out.Fake
+		*out = new(FakeProvider)
+		(*in).DeepCopyInto(*out)
+	}
 }
 }
 
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretStoreProvider.
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretStoreProvider.

+ 23 - 0
deploy/crds/external-secrets.io_clustersecretstores.yaml

@@ -380,6 +380,29 @@ spec:
                     required:
                     required:
                     - vaultUrl
                     - vaultUrl
                     type: object
                     type: object
+                  fake:
+                    description: Fake configures a store with static key/value pairs
+                    properties:
+                      data:
+                        items:
+                          properties:
+                            key:
+                              type: string
+                            value:
+                              type: string
+                            valueMap:
+                              additionalProperties:
+                                type: string
+                              type: object
+                            version:
+                              type: string
+                          required:
+                          - key
+                          type: object
+                        type: array
+                    required:
+                    - data
+                    type: object
                   gcpsm:
                   gcpsm:
                     description: GCPSM configures this store to sync secrets using
                     description: GCPSM configures this store to sync secrets using
                       Google Cloud Platform Secret Manager provider
                       Google Cloud Platform Secret Manager provider

+ 23 - 0
deploy/crds/external-secrets.io_secretstores.yaml

@@ -380,6 +380,29 @@ spec:
                     required:
                     required:
                     - vaultUrl
                     - vaultUrl
                     type: object
                     type: object
+                  fake:
+                    description: Fake configures a store with static key/value pairs
+                    properties:
+                      data:
+                        items:
+                          properties:
+                            key:
+                              type: string
+                            value:
+                              type: string
+                            valueMap:
+                              additionalProperties:
+                                type: string
+                              type: object
+                            version:
+                              type: string
+                          required:
+                          - key
+                          type: object
+                        type: array
+                    required:
+                    - data
+                    type: object
                   gcpsm:
                   gcpsm:
                     description: GCPSM configures this store to sync secrets using
                     description: GCPSM configures this store to sync secrets using
                       Google Cloud Platform Secret Manager provider
                       Google Cloud Platform Secret Manager provider

+ 76 - 0
docs/contributing-process.md

@@ -31,6 +31,82 @@ for the lifecycle of the PR: review, merging, ping on inactivity, close.
 We close pull requests or issues if there is no response from the author for
 We close pull requests or issues if there is no response from the author for
 a period of time. Feel free to reopen if you want to get back on it.
 a period of time. Feel free to reopen if you want to get back on it.
 
 
+### Triggering e2e tests
+
+We have an extensive set of e2e tests that test the integration with *real* cloud provider APIs.
+Maintainers must trigger these kind of tests manually for PRs that come from forked repositories. These tests run inside a `kind` cluster in the GitHub Actions runner:
+
+```
+/ok-to-test sha=xxxxxx
+```
+
+#### Executing e2e tests locally
+
+You have to prepare your shell environment with the necessary variables so the e2e test
+runner knows what credentials to use. See `e2e/run.sh` for the variables that are passed in.
+If you e.g. want to test AWS integration make sure set all `AWS_*` variables mentioned
+in that file.
+
+Use [ginkgo labels](https://onsi.github.io/ginkgo/#spec-labels) to select the tests
+you want to execute. You have to specify `!managed` to ensure that you do not
+run managed tests.
+
+```
+make test.e2e GINKGO_LABELS='gcp&&!managed'
+```
+
+#### Managed Kubernetes e2e tests
+
+There's another suite of e2e tests that integrate with managed Kuberentes offerings.
+They create real infrastructure at a cloud provider and deploy the controller
+into that environment.
+This is necessary to test the authentication integration
+([GCP Worklaod Identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity),
+[EKS IRSA](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html)...).
+
+These tests are time intensive (~20-45min) and must be triggered manually by
+a maintainer when a particular provider or authentication mechanism was changed:
+
+```
+/ok-to-test-managed sha=xxxxxx provider=aws
+# or
+/ok-to-test-managed sha=xxxxxx provider=gcp
+```
+
+Both tests can run in parallel. Once started they add a dynamic GitHub check `integration-managed-(gcp|aws)` to the PR that triggered the test.
+
+
+### Executing Managed Kubernetes e2e tests locally
+
+You have to prepare your shell environment with the necessary variables so the e2e
+test runner knows what credentials to use. See `.github/workflows/e2e-managed.yml`
+for the variables that are passed in. If you e.g. want to test AWS integration make
+sure set all variables containing `AWS_*` and `TF_VAR_AWS_*` mentioned in that file.
+
+Then execute `tf.apply.aws` or `tf.apply.gcp` to create the infrastructure.
+
+```
+make tf.apply.aws
+```
+
+Then run the `managed` testsuite. You will need push permissions to the external-secrets ghcr repository. You can set `IMAGE_REGISTRY` to control which image registry is used to store the controller and e2e test images in.
+
+You also have to setup a proper Kubeconfig so the e2e test pod gets deployed into the managed cluster.
+
+```
+aws eks update-kubeconfig --name ${AWS_CLUSTER_NAME}
+or
+gcloud container clusters get-credentials ${GCP_GKE_CLUSTER} --region europe-west1-b
+```
+
+Use [ginkgo labels](https://onsi.github.io/ginkgo/#spec-labels) to select the tests
+you want to execute.
+
+```
+# you may have to set IMAGE_REGISTRY=docker.io/your-user/external-secrets
+make test.e2e.managed GINKGO_LABELS='gcp'
+```
+
 ## Proposal Process
 ## Proposal Process
 Before we introduce significant changes to the project we want to gather feedback
 Before we introduce significant changes to the project we want to gather feedback
 from the community to ensure that we progress in the right direction before we
 from the community to ensure that we progress in the right direction before we

+ 26 - 0
docs/provider-fake.md

@@ -0,0 +1,26 @@
+We provide a `fake` implementation to help with testing. This provider returns static key/value pairs and nothing else.
+To use the `fake` provider simply create a `SecretStore` or `ClusterSecretStore` and configure it like in the following example:
+
+!!! note inline end
+    The provider returns static data configured in `value` or `valueMap`. You can define a `version`, too. If set the `remoteRef` from an ExternalSecret must match otherwise no value is returned.
+
+```yaml
+{% include 'fake-provider-store.yaml' %}
+```
+
+Please note that `value` is intended for exclusive use with `data` and `valueMap` for `dataFrom`.
+Here is an example `ExternalSecret` that displays this behavior:
+
+!!! warning inline end
+    This provider supports specifying different `data[].version` configurations. However, `data[].property` is ignored.
+
+```yaml
+{% include 'fake-provider-es.yaml' %}
+```
+
+This results in the following secret:
+
+
+```yaml
+{% include 'fake-provider-secret.yaml' %}
+```

+ 18 - 0
docs/snippets/fake-provider-es.yaml

@@ -0,0 +1,18 @@
+apiVersion: external-secrets.io/v1alpha1
+kind: ExternalSecret
+metadata:
+  name: example
+spec:
+  refreshInterval: 1h
+  secretStoreRef:
+    name: fake
+    kind: ClusterSecretStore
+  target:
+    name: secret-to-be-created
+  data:
+  - secretKey: foo_bar
+    remoteRef:
+      key: /foo/bar
+      version: v1
+  dataFrom:
+  - key: /foo/baz

+ 9 - 0
docs/snippets/fake-provider-secret.yaml

@@ -0,0 +1,9 @@
+apiVersion: v1
+kind: Secret
+metadata:
+  name: secret-to-be-created
+  namespace: default
+data:
+  foo_bar: SEVMTE8x # HELLO1  (via data)
+  foo: ZXhhbXBsZQ== # example (via dataFrom)
+  other: dGhpbmc=   # thing   (via dataFrom)

+ 20 - 0
docs/snippets/fake-provider-store.yaml

@@ -0,0 +1,20 @@
+apiVersion: external-secrets.io/v1alpha1
+kind: ClusterSecretStore
+metadata:
+  name: fake
+spec:
+  provider:
+    fake:
+      data:
+      - key: "/foo/bar"
+        value: "HELLO1"
+        version: "v1"
+      - key: "/foo/bar"
+        value: "HELLO2"
+        version: "v2"
+      - key: "/foo/baz"
+        valueMap:
+          foo: example
+          other: thing
+
+

+ 336 - 0
docs/spec.md

@@ -714,6 +714,237 @@ string
 <td></td>
 <td></td>
 </tr></tbody>
 </tr></tbody>
 </table>
 </table>
+<h3 id="external-secrets.io/v1alpha1.ClusterExternalSecret">ClusterExternalSecret
+</h3>
+<p>
+<p>ClusterExternalSecret is the Schema for the clusterexternalsecrets API.</p>
+</p>
+<table>
+<thead>
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<code>metadata</code></br>
+<em>
+<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#objectmeta-v1-meta">
+Kubernetes meta/v1.ObjectMeta
+</a>
+</em>
+</td>
+<td>
+Refer to the Kubernetes API documentation for the fields of the
+<code>metadata</code> field.
+</td>
+</tr>
+<tr>
+<td>
+<code>spec</code></br>
+<em>
+<a href="#external-secrets.io/v1alpha1.ClusterExternalSecretSpec">
+ClusterExternalSecretSpec
+</a>
+</em>
+</td>
+<td>
+<br/>
+<br/>
+<table>
+<tr>
+<td>
+<code>externalSecretSpec</code></br>
+<em>
+<a href="#external-secrets.io/v1alpha1.ExternalSecretSpec">
+ExternalSecretSpec
+</a>
+</em>
+</td>
+<td>
+<p>The spec for the ExternalSecrets to be created</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>externalSecretName</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>The name of the external secrets to be created defaults to the name of the ClusterExternalSecret</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>namespaceSelector</code></br>
+<em>
+<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#labelselector-v1-meta">
+Kubernetes meta/v1.LabelSelector
+</a>
+</em>
+</td>
+<td>
+<p>The labels to select by to find the Namespaces to create the ExternalSecrets in.</p>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+<td>
+<code>status</code></br>
+<em>
+<a href="#external-secrets.io/v1alpha1.ClusterExternalSecretStatus">
+ClusterExternalSecretStatus
+</a>
+</em>
+</td>
+<td>
+</td>
+</tr>
+</tbody>
+</table>
+<h3 id="external-secrets.io/v1alpha1.ClusterExternalSecretConditionType">ClusterExternalSecretConditionType
+(<code>string</code> alias)</p></h3>
+<p>
+(<em>Appears on:</em>
+<a href="#external-secrets.io/v1alpha1.ClusterExternalSecretStatus">ClusterExternalSecretStatus</a>)
+</p>
+<p>
+</p>
+<table>
+<thead>
+<tr>
+<th>Value</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody><tr><td><p>&#34;NotReady&#34;</p></td>
+<td></td>
+</tr><tr><td><p>&#34;PartiallyReady&#34;</p></td>
+<td></td>
+</tr><tr><td><p>&#34;Ready&#34;</p></td>
+<td></td>
+</tr></tbody>
+</table>
+<h3 id="external-secrets.io/v1alpha1.ClusterExternalSecretSpec">ClusterExternalSecretSpec
+</h3>
+<p>
+(<em>Appears on:</em>
+<a href="#external-secrets.io/v1alpha1.ClusterExternalSecret">ClusterExternalSecret</a>)
+</p>
+<p>
+<p>ClusterExternalSecretSpec defines the desired state of ClusterExternalSecret.</p>
+</p>
+<table>
+<thead>
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<code>externalSecretSpec</code></br>
+<em>
+<a href="#external-secrets.io/v1alpha1.ExternalSecretSpec">
+ExternalSecretSpec
+</a>
+</em>
+</td>
+<td>
+<p>The spec for the ExternalSecrets to be created</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>externalSecretName</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>The name of the external secrets to be created defaults to the name of the ClusterExternalSecret</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>namespaceSelector</code></br>
+<em>
+<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#labelselector-v1-meta">
+Kubernetes meta/v1.LabelSelector
+</a>
+</em>
+</td>
+<td>
+<p>The labels to select by to find the Namespaces to create the ExternalSecrets in.</p>
+</td>
+</tr>
+</tbody>
+</table>
+<h3 id="external-secrets.io/v1alpha1.ClusterExternalSecretStatus">ClusterExternalSecretStatus
+</h3>
+<p>
+(<em>Appears on:</em>
+<a href="#external-secrets.io/v1alpha1.ClusterExternalSecret">ClusterExternalSecret</a>)
+</p>
+<p>
+<p>ClusterExternalSecretStatus defines the observed state of ClusterExternalSecret.</p>
+</p>
+<table>
+<thead>
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<code>type</code></br>
+<em>
+<a href="#external-secrets.io/v1alpha1.ClusterExternalSecretConditionType">
+ClusterExternalSecretConditionType
+</a>
+</em>
+</td>
+<td>
+</td>
+</tr>
+<tr>
+<td>
+<code>status</code></br>
+<em>
+<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#conditionstatus-v1-core">
+Kubernetes core/v1.ConditionStatus
+</a>
+</em>
+</td>
+<td>
+</td>
+</tr>
+<tr>
+<td>
+<code>externalSecretStatuses</code></br>
+<em>
+<a href="#external-secrets.io/v1alpha1.ExternalSecretStatus">
+[]ExternalSecretStatus
+</a>
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+</td>
+</tr>
+</tbody>
+</table>
 <h3 id="external-secrets.io/v1alpha1.ClusterSecretStore">ClusterSecretStore
 <h3 id="external-secrets.io/v1alpha1.ClusterSecretStore">ClusterSecretStore
 </h3>
 </h3>
 <p>
 <p>
@@ -1084,6 +1315,7 @@ string
 </h3>
 </h3>
 <p>
 <p>
 (<em>Appears on:</em>
 (<em>Appears on:</em>
+<a href="#external-secrets.io/v1alpha1.ClusterExternalSecretSpec">ClusterExternalSecretSpec</a>, 
 <a href="#external-secrets.io/v1alpha1.ExternalSecret">ExternalSecret</a>)
 <a href="#external-secrets.io/v1alpha1.ExternalSecret">ExternalSecret</a>)
 </p>
 </p>
 <p>
 <p>
@@ -1171,6 +1403,7 @@ If multiple entries are specified, the Secret keys are merged in the specified o
 </h3>
 </h3>
 <p>
 <p>
 (<em>Appears on:</em>
 (<em>Appears on:</em>
+<a href="#external-secrets.io/v1alpha1.ClusterExternalSecretStatus">ClusterExternalSecretStatus</a>, 
 <a href="#external-secrets.io/v1alpha1.ExternalSecret">ExternalSecret</a>)
 <a href="#external-secrets.io/v1alpha1.ExternalSecret">ExternalSecret</a>)
 </p>
 </p>
 <p>
 <p>
@@ -1486,6 +1719,95 @@ map[string]string
 </tr>
 </tr>
 </tbody>
 </tbody>
 </table>
 </table>
+<h3 id="external-secrets.io/v1alpha1.FakeProvider">FakeProvider
+</h3>
+<p>
+(<em>Appears on:</em>
+<a href="#external-secrets.io/v1alpha1.SecretStoreProvider">SecretStoreProvider</a>)
+</p>
+<p>
+<p>FakeProvider configures a fake provider that returns static values</p>
+</p>
+<table>
+<thead>
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<code>data</code></br>
+<em>
+<a href="#external-secrets.io/v1alpha1.FakeProviderData">
+[]FakeProviderData
+</a>
+</em>
+</td>
+<td>
+</td>
+</tr>
+</tbody>
+</table>
+<h3 id="external-secrets.io/v1alpha1.FakeProviderData">FakeProviderData
+</h3>
+<p>
+(<em>Appears on:</em>
+<a href="#external-secrets.io/v1alpha1.FakeProvider">FakeProvider</a>)
+</p>
+<p>
+</p>
+<table>
+<thead>
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<code>key</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+</td>
+</tr>
+<tr>
+<td>
+<code>value</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+</td>
+</tr>
+<tr>
+<td>
+<code>valueMap</code></br>
+<em>
+map[string]string
+</em>
+</td>
+<td>
+</td>
+</tr>
+<tr>
+<td>
+<code>version</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+</td>
+</tr>
+</tbody>
+</table>
 <h3 id="external-secrets.io/v1alpha1.GCPSMAuth">GCPSMAuth
 <h3 id="external-secrets.io/v1alpha1.GCPSMAuth">GCPSMAuth
 </h3>
 </h3>
 <p>
 <p>
@@ -2310,6 +2632,20 @@ WebhookProvider
 <p>Webhook configures this store to sync secrets using a generic templated webhook</p>
 <p>Webhook configures this store to sync secrets using a generic templated webhook</p>
 </td>
 </td>
 </tr>
 </tr>
+<tr>
+<td>
+<code>fake</code></br>
+<em>
+<a href="#external-secrets.io/v1alpha1.FakeProvider">
+FakeProvider
+</a>
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>Fake configures a store with static key/value pairs</p>
+</td>
+</tr>
 </tbody>
 </tbody>
 </table>
 </table>
 <h3 id="external-secrets.io/v1alpha1.SecretStoreRef">SecretStoreRef
 <h3 id="external-secrets.io/v1alpha1.SecretStoreRef">SecretStoreRef

+ 1 - 1
e2e/Makefile

@@ -2,7 +2,7 @@ MAKEFLAGS   += --warn-undefined-variables
 SHELL       := /bin/bash
 SHELL       := /bin/bash
 .SHELLFLAGS := -euo pipefail -c
 .SHELLFLAGS := -euo pipefail -c
 
 
-KIND_IMG       = "kindest/node:v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6"
+KIND_IMG       = "kindest/node:v1.23.3@sha256:0df8215895129c0d3221cda19847d1296c4f29ec93487339149333bd9d899e5a"
 BUILD_ARGS     ?=
 BUILD_ARGS     ?=
 
 
 export E2E_IMAGE_REGISTRY ?= ghcr.io/external-secrets/external-secrets-e2e
 export E2E_IMAGE_REGISTRY ?= ghcr.io/external-secrets/external-secrets-e2e

+ 97 - 0
e2e/suite/aws/common.go

@@ -0,0 +1,97 @@
+/*
+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
+
+    http://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 common
+
+import (
+	"context"
+
+	// nolint
+	. "github.com/onsi/gomega"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
+	esmetav1 "github.com/external-secrets/external-secrets/apis/meta/v1"
+	"github.com/external-secrets/external-secrets/e2e/framework"
+)
+
+const (
+	WithReferencedIRSA          = "with referenced IRSA"
+	WithMountedIRSA             = "with mounted IRSA"
+	StaticCredentialsSecretName = "provider-secret"
+)
+
+func ReferencedIRSAStoreName(f *framework.Framework) string {
+	return "irsa-ref-" + f.Namespace.Name
+}
+
+func MountedIRSAStoreName(f *framework.Framework) string {
+	return "irsa-mounted-" + f.Namespace.Name
+}
+
+func UseClusterSecretStore(tc *framework.TestCase) {
+	tc.ExternalSecret.Spec.SecretStoreRef.Kind = esv1alpha1.ClusterSecretStoreKind
+	tc.ExternalSecret.Spec.SecretStoreRef.Name = ReferencedIRSAStoreName(tc.Framework)
+}
+
+func UseMountedIRSAStore(tc *framework.TestCase) {
+	tc.ExternalSecret.Spec.SecretStoreRef.Kind = esv1alpha1.SecretStoreKind
+	tc.ExternalSecret.Spec.SecretStoreRef.Name = MountedIRSAStoreName(tc.Framework)
+}
+
+// StaticStore is namespaced and references
+// static credentials from a secret.
+func SetupStaticStore(f *framework.Framework, kid, sak, region string, serviceType esv1alpha1.AWSServiceType) {
+	awsCreds := &corev1.Secret{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      StaticCredentialsSecretName,
+			Namespace: f.Namespace.Name,
+		},
+		StringData: map[string]string{
+			"kid": kid,
+			"sak": sak,
+		},
+	}
+	err := f.CRClient.Create(context.Background(), awsCreds)
+	Expect(err).ToNot(HaveOccurred())
+
+	secretStore := &esv1alpha1.SecretStore{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      f.Namespace.Name,
+			Namespace: f.Namespace.Name,
+		},
+		Spec: esv1alpha1.SecretStoreSpec{
+			Provider: &esv1alpha1.SecretStoreProvider{
+				AWS: &esv1alpha1.AWSProvider{
+					Service: serviceType,
+					Region:  region,
+					Auth: esv1alpha1.AWSAuth{
+						SecretRef: &esv1alpha1.AWSAuthSecretRef{
+							AccessKeyID: esmetav1.SecretKeySelector{
+								Name: StaticCredentialsSecretName,
+								Key:  "kid",
+							},
+							SecretAccessKey: esmetav1.SecretKeySelector{
+								Name: StaticCredentialsSecretName,
+								Key:  "sak",
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	err = f.CRClient.Create(context.Background(), secretStore)
+	Expect(err).ToNot(HaveOccurred())
+}

+ 45 - 0
e2e/suite/aws/parameterstore/parameterstore.go

@@ -0,0 +1,45 @@
+/*
+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
+
+    http://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 aws
+
+import (
+
+	// nolint
+	. "github.com/onsi/ginkgo/v2"
+
+	"github.com/external-secrets/external-secrets/e2e/framework"
+	"github.com/external-secrets/external-secrets/e2e/suite/common"
+)
+
+var _ = Describe("[aws] ", Label("aws", "parameterstore"), func() {
+	f := framework.New("eso-aws-ps")
+	prov := NewFromEnv(f)
+
+	DescribeTable("sync secrets",
+		framework.TableFunc(f,
+			prov),
+		Entry(common.SimpleDataSync(f)),
+		Entry(common.NestedJSONWithGJSON(f)),
+		Entry(common.JSONDataFromSync(f)),
+		Entry(common.JSONDataWithProperty(f)),
+		Entry(common.JSONDataWithTemplate(f)),
+		Entry(common.DockerJSONConfig(f)),
+		Entry(common.DataPropertyDockerconfigJSON(f)),
+		Entry(common.SSHKeySync(f)),
+		Entry(common.SSHKeySyncDataProperty(f)),
+		Entry(common.SyncWithoutTargetName(f)),
+		Entry(common.JSONDataWithoutTargetName(f)),
+	)
+})

+ 85 - 0
e2e/suite/aws/parameterstore/parameterstore_managed.go

@@ -0,0 +1,85 @@
+/*
+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
+
+    http://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 aws
+
+import (
+
+	// nolint
+	. "github.com/onsi/ginkgo/v2"
+
+	"github.com/external-secrets/external-secrets/e2e/framework"
+	"github.com/external-secrets/external-secrets/e2e/framework/addon"
+	awscommon "github.com/external-secrets/external-secrets/e2e/suite/aws"
+	"github.com/external-secrets/external-secrets/e2e/suite/common"
+)
+
+// here we use the global eso instance
+// that uses the service account in the default namespace
+// which was created by terraform.
+var _ = Describe("[awsmanaged] IRSA via referenced service account", Label("aws", "parameterstore", "managed"), func() {
+	f := framework.New("eso-aws-ps-managed")
+	prov := NewFromEnv(f)
+
+	// nolint
+	DescribeTable("sync secrets",
+		framework.TableFunc(f,
+			prov),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.SimpleDataSync, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.NestedJSONWithGJSON, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataFromSync, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataWithProperty, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataWithTemplate, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.DockerJSONConfig, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.DataPropertyDockerconfigJSON, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.SSHKeySync, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.SSHKeySyncDataProperty, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.SyncWithoutTargetName, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataWithoutTargetName, awscommon.UseClusterSecretStore),
+	)
+})
+
+// here we create a central eso instance in the default namespace
+// that mounts the service account which was created by terraform.
+var _ = Describe("[awsmanaged] with mounted IRSA", Label("aws", "parameterstore", "managed"), func() {
+	f := framework.New("eso-aws-ps-irsa-managed")
+	prov := NewFromEnv(f)
+
+	// each test case gets its own ESO instance
+	BeforeEach(func() {
+		f.Install(addon.NewESO(
+			addon.WithControllerClass(f.BaseName),
+			addon.WithServiceAccount(prov.ServiceAccountName),
+			addon.WithReleaseName(f.Namespace.Name),
+			addon.WithNamespace("default"),
+		))
+	})
+
+	// nolint
+	DescribeTable("sync secrets",
+		framework.TableFunc(f,
+			prov),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.SimpleDataSync, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.NestedJSONWithGJSON, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataFromSync, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataWithProperty, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataWithTemplate, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.DockerJSONConfig, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.DataPropertyDockerconfigJSON, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.SSHKeySync, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.SSHKeySyncDataProperty, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.SyncWithoutTargetName, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataWithoutTargetName, awscommon.UseMountedIRSAStore),
+	)
+})

+ 165 - 0
e2e/suite/aws/parameterstore/provider.go

@@ -0,0 +1,165 @@
+/*
+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
+
+    http://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 aws
+
+import (
+	"context"
+	"os"
+
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/aws/credentials"
+	"github.com/aws/aws-sdk-go/aws/session"
+	"github.com/aws/aws-sdk-go/service/ssm"
+
+	//nolint
+	. "github.com/onsi/ginkgo/v2"
+
+	// nolint
+	. "github.com/onsi/gomega"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
+
+	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
+	esmetav1 "github.com/external-secrets/external-secrets/apis/meta/v1"
+	"github.com/external-secrets/external-secrets/e2e/framework"
+	"github.com/external-secrets/external-secrets/e2e/framework/log"
+	common "github.com/external-secrets/external-secrets/e2e/suite/aws"
+)
+
+type Provider struct {
+	ServiceAccountName      string
+	ServiceAccountNamespace string
+
+	region    string
+	client    *ssm.SSM
+	framework *framework.Framework
+}
+
+func NewProvider(f *framework.Framework, kid, sak, region, saName, saNamespace string) *Provider {
+	sess, err := session.NewSessionWithOptions(session.Options{
+		Config: aws.Config{
+			Credentials: credentials.NewStaticCredentials(kid, sak, ""),
+			Region:      aws.String(region),
+		},
+	})
+	if err != nil {
+		Fail(err.Error())
+	}
+	sm := ssm.New(sess)
+	prov := &Provider{
+		ServiceAccountName:      saName,
+		ServiceAccountNamespace: saNamespace,
+		region:                  region,
+		client:                  sm,
+		framework:               f,
+	}
+
+	BeforeEach(func() {
+		common.SetupStaticStore(f, kid, sak, region, esv1alpha1.AWSServiceParameterStore)
+		prov.SetupReferencedIRSAStore()
+		prov.SetupMountedIRSAStore()
+	})
+
+	AfterEach(func() {
+		// Cleanup ClusterSecretStore
+		err := prov.framework.CRClient.Delete(context.Background(), &esv1alpha1.ClusterSecretStore{
+			ObjectMeta: metav1.ObjectMeta{
+				Name: common.ReferencedIRSAStoreName(f),
+			},
+		})
+		Expect(err).ToNot(HaveOccurred())
+	})
+
+	return prov
+}
+
+func NewFromEnv(f *framework.Framework) *Provider {
+	kid := os.Getenv("AWS_ACCESS_KEY_ID")
+	sak := os.Getenv("AWS_SECRET_ACCESS_KEY")
+	region := "eu-west-1"
+	saName := os.Getenv("AWS_SA_NAME")
+	saNamespace := os.Getenv("AWS_SA_NAMESPACE")
+	return NewProvider(f, kid, sak, region, saName, saNamespace)
+}
+
+// CreateSecret creates a secret at the provider.
+func (s *Provider) CreateSecret(key, val string) {
+	_, err := s.client.PutParameter(&ssm.PutParameterInput{
+		Name:     aws.String(key),
+		Value:    aws.String(val),
+		DataType: aws.String("text"),
+		Type:     aws.String("String"),
+	})
+	Expect(err).ToNot(HaveOccurred())
+}
+
+// DeleteSecret deletes a secret at the provider.
+func (s *Provider) DeleteSecret(key string) {
+	_, err := s.client.DeleteParameter(&ssm.DeleteParameterInput{
+		Name: aws.String(key),
+	})
+	Expect(err).ToNot(HaveOccurred())
+}
+
+// MountedIRSAStore is a SecretStore without auth config
+// ESO relies on the pod-mounted ServiceAccount when using this store.
+func (s *Provider) SetupMountedIRSAStore() {
+	secretStore := &esv1alpha1.SecretStore{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      common.MountedIRSAStoreName(s.framework),
+			Namespace: s.framework.Namespace.Name,
+		},
+		Spec: esv1alpha1.SecretStoreSpec{
+			Provider: &esv1alpha1.SecretStoreProvider{
+				AWS: &esv1alpha1.AWSProvider{
+					Service: esv1alpha1.AWSServiceParameterStore,
+					Region:  s.region,
+					Auth:    esv1alpha1.AWSAuth{},
+				},
+			},
+		},
+	}
+	err := s.framework.CRClient.Create(context.Background(), secretStore)
+	Expect(err).ToNot(HaveOccurred())
+}
+
+// ReferncedIRSAStore is a ClusterStore
+// that references a (IRSA-) ServiceAccount in the default namespace.
+func (s *Provider) SetupReferencedIRSAStore() {
+	log.Logf("creating IRSA ClusterSecretStore %s", s.framework.Namespace.Name)
+	secretStore := &esv1alpha1.ClusterSecretStore{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: common.ReferencedIRSAStoreName(s.framework),
+		},
+	}
+	_, err := controllerutil.CreateOrUpdate(context.Background(), s.framework.CRClient, secretStore, func() error {
+		secretStore.Spec.Provider = &esv1alpha1.SecretStoreProvider{
+			AWS: &esv1alpha1.AWSProvider{
+				Service: esv1alpha1.AWSServiceParameterStore,
+				Region:  s.region,
+				Auth: esv1alpha1.AWSAuth{
+					JWTAuth: &esv1alpha1.AWSJWTAuth{
+						ServiceAccountRef: &esmetav1.ServiceAccountSelector{
+							Name:      s.ServiceAccountName,
+							Namespace: &s.ServiceAccountNamespace,
+						},
+					},
+				},
+			},
+		}
+		return nil
+	})
+	Expect(err).ToNot(HaveOccurred())
+}

+ 14 - 76
e2e/suite/aws/provider.go → e2e/suite/aws/secretsmanager/provider.go

@@ -29,7 +29,6 @@ import (
 
 
 	// nolint
 	// nolint
 	. "github.com/onsi/gomega"
 	. "github.com/onsi/gomega"
-	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
 
 
@@ -37,24 +36,19 @@ import (
 	esmetav1 "github.com/external-secrets/external-secrets/apis/meta/v1"
 	esmetav1 "github.com/external-secrets/external-secrets/apis/meta/v1"
 	"github.com/external-secrets/external-secrets/e2e/framework"
 	"github.com/external-secrets/external-secrets/e2e/framework"
 	"github.com/external-secrets/external-secrets/e2e/framework/log"
 	"github.com/external-secrets/external-secrets/e2e/framework/log"
+	common "github.com/external-secrets/external-secrets/e2e/suite/aws"
 )
 )
 
 
-type SMProvider struct {
+type Provider struct {
 	ServiceAccountName      string
 	ServiceAccountName      string
 	ServiceAccountNamespace string
 	ServiceAccountNamespace string
 
 
-	kid       string
-	sak       string
 	region    string
 	region    string
 	client    *secretsmanager.SecretsManager
 	client    *secretsmanager.SecretsManager
 	framework *framework.Framework
 	framework *framework.Framework
 }
 }
 
 
-const (
-	staticCredentialsSecretName = "provider-secret"
-)
-
-func NewSMProvider(f *framework.Framework, kid, sak, region, saName, saNamespace string) *SMProvider {
+func NewProvider(f *framework.Framework, kid, sak, region, saName, saNamespace string) *Provider {
 	sess, err := session.NewSessionWithOptions(session.Options{
 	sess, err := session.NewSessionWithOptions(session.Options{
 		Config: aws.Config{
 		Config: aws.Config{
 			Credentials: credentials.NewStaticCredentials(kid, sak, ""),
 			Credentials: credentials.NewStaticCredentials(kid, sak, ""),
@@ -65,18 +59,16 @@ func NewSMProvider(f *framework.Framework, kid, sak, region, saName, saNamespace
 		Fail(err.Error())
 		Fail(err.Error())
 	}
 	}
 	sm := secretsmanager.New(sess)
 	sm := secretsmanager.New(sess)
-	prov := &SMProvider{
+	prov := &Provider{
 		ServiceAccountName:      saName,
 		ServiceAccountName:      saName,
 		ServiceAccountNamespace: saNamespace,
 		ServiceAccountNamespace: saNamespace,
-		kid:                     kid,
-		sak:                     sak,
 		region:                  region,
 		region:                  region,
 		client:                  sm,
 		client:                  sm,
 		framework:               f,
 		framework:               f,
 	}
 	}
 
 
 	BeforeEach(func() {
 	BeforeEach(func() {
-		prov.SetupStaticStore()
+		common.SetupStaticStore(f, kid, sak, region, esv1alpha1.AWSServiceSecretsManager)
 		prov.SetupReferencedIRSAStore()
 		prov.SetupReferencedIRSAStore()
 		prov.SetupMountedIRSAStore()
 		prov.SetupMountedIRSAStore()
 	})
 	})
@@ -85,7 +77,7 @@ func NewSMProvider(f *framework.Framework, kid, sak, region, saName, saNamespace
 		// Cleanup ClusterSecretStore
 		// Cleanup ClusterSecretStore
 		err := prov.framework.CRClient.Delete(context.Background(), &esv1alpha1.ClusterSecretStore{
 		err := prov.framework.CRClient.Delete(context.Background(), &esv1alpha1.ClusterSecretStore{
 			ObjectMeta: metav1.ObjectMeta{
 			ObjectMeta: metav1.ObjectMeta{
-				Name: prov.ReferencedIRSAStoreName(),
+				Name: common.ReferencedIRSAStoreName(f),
 			},
 			},
 		})
 		})
 		Expect(err).ToNot(HaveOccurred())
 		Expect(err).ToNot(HaveOccurred())
@@ -94,17 +86,17 @@ func NewSMProvider(f *framework.Framework, kid, sak, region, saName, saNamespace
 	return prov
 	return prov
 }
 }
 
 
-func NewFromEnv(f *framework.Framework) *SMProvider {
+func NewFromEnv(f *framework.Framework) *Provider {
 	kid := os.Getenv("AWS_ACCESS_KEY_ID")
 	kid := os.Getenv("AWS_ACCESS_KEY_ID")
 	sak := os.Getenv("AWS_SECRET_ACCESS_KEY")
 	sak := os.Getenv("AWS_SECRET_ACCESS_KEY")
 	region := "eu-west-1"
 	region := "eu-west-1"
 	saName := os.Getenv("AWS_SA_NAME")
 	saName := os.Getenv("AWS_SA_NAME")
 	saNamespace := os.Getenv("AWS_SA_NAMESPACE")
 	saNamespace := os.Getenv("AWS_SA_NAMESPACE")
-	return NewSMProvider(f, kid, sak, region, saName, saNamespace)
+	return NewProvider(f, kid, sak, region, saName, saNamespace)
 }
 }
 
 
 // CreateSecret creates a secret at the provider.
 // CreateSecret creates a secret at the provider.
-func (s *SMProvider) CreateSecret(key, val string) {
+func (s *Provider) CreateSecret(key, val string) {
 	// we re-use some secret names throughout our test suite
 	// we re-use some secret names throughout our test suite
 	// due to the fact that there is a short delay before the secret is actually deleted
 	// due to the fact that there is a short delay before the secret is actually deleted
 	// we have to retry creating the secret
 	// we have to retry creating the secret
@@ -129,7 +121,7 @@ func (s *SMProvider) CreateSecret(key, val string) {
 // DeleteSecret deletes a secret at the provider.
 // DeleteSecret deletes a secret at the provider.
 // There may be a short delay between calling this function
 // There may be a short delay between calling this function
 // and the removal of the secret on the provider side.
 // and the removal of the secret on the provider side.
-func (s *SMProvider) DeleteSecret(key string) {
+func (s *Provider) DeleteSecret(key string) {
 	log.Logf("deleting secret %s", key)
 	log.Logf("deleting secret %s", key)
 	_, err := s.client.DeleteSecret(&secretsmanager.DeleteSecretInput{
 	_, err := s.client.DeleteSecret(&secretsmanager.DeleteSecretInput{
 		SecretId:                   aws.String(key),
 		SecretId:                   aws.String(key),
@@ -140,10 +132,10 @@ func (s *SMProvider) DeleteSecret(key string) {
 
 
 // MountedIRSAStore is a SecretStore without auth config
 // MountedIRSAStore is a SecretStore without auth config
 // ESO relies on the pod-mounted ServiceAccount when using this store.
 // ESO relies on the pod-mounted ServiceAccount when using this store.
-func (s *SMProvider) SetupMountedIRSAStore() {
+func (s *Provider) SetupMountedIRSAStore() {
 	secretStore := &esv1alpha1.SecretStore{
 	secretStore := &esv1alpha1.SecretStore{
 		ObjectMeta: metav1.ObjectMeta{
 		ObjectMeta: metav1.ObjectMeta{
-			Name:      s.MountedIRSAStoreName(),
+			Name:      common.MountedIRSAStoreName(s.framework),
 			Namespace: s.framework.Namespace.Name,
 			Namespace: s.framework.Namespace.Name,
 		},
 		},
 		Spec: esv1alpha1.SecretStoreSpec{
 		Spec: esv1alpha1.SecretStoreSpec{
@@ -160,17 +152,13 @@ func (s *SMProvider) SetupMountedIRSAStore() {
 	Expect(err).ToNot(HaveOccurred())
 	Expect(err).ToNot(HaveOccurred())
 }
 }
 
 
-func (s *SMProvider) MountedIRSAStoreName() string {
-	return "irsa-mounted-" + s.framework.Namespace.Name
-}
-
 // ReferncedIRSAStore is a ClusterStore
 // ReferncedIRSAStore is a ClusterStore
 // that references a (IRSA-) ServiceAccount in the default namespace.
 // that references a (IRSA-) ServiceAccount in the default namespace.
-func (s *SMProvider) SetupReferencedIRSAStore() {
+func (s *Provider) SetupReferencedIRSAStore() {
 	log.Logf("creating IRSA ClusterSecretStore %s", s.framework.Namespace.Name)
 	log.Logf("creating IRSA ClusterSecretStore %s", s.framework.Namespace.Name)
 	secretStore := &esv1alpha1.ClusterSecretStore{
 	secretStore := &esv1alpha1.ClusterSecretStore{
 		ObjectMeta: metav1.ObjectMeta{
 		ObjectMeta: metav1.ObjectMeta{
-			Name: s.ReferencedIRSAStoreName(),
+			Name: common.ReferencedIRSAStoreName(s.framework),
 		},
 		},
 	}
 	}
 	_, err := controllerutil.CreateOrUpdate(context.Background(), s.framework.CRClient, secretStore, func() error {
 	_, err := controllerutil.CreateOrUpdate(context.Background(), s.framework.CRClient, secretStore, func() error {
@@ -192,53 +180,3 @@ func (s *SMProvider) SetupReferencedIRSAStore() {
 	})
 	})
 	Expect(err).ToNot(HaveOccurred())
 	Expect(err).ToNot(HaveOccurred())
 }
 }
-
-func (s *SMProvider) ReferencedIRSAStoreName() string {
-	return "irsa-ref-" + s.framework.Namespace.Name
-}
-
-// StaticStore is namespaced and references
-// static credentials from a secret.
-func (s *SMProvider) SetupStaticStore() {
-	awsCreds := &v1.Secret{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      staticCredentialsSecretName,
-			Namespace: s.framework.Namespace.Name,
-		},
-		StringData: map[string]string{
-			"kid": s.kid,
-			"sak": s.sak,
-		},
-	}
-	err := s.framework.CRClient.Create(context.Background(), awsCreds)
-	Expect(err).ToNot(HaveOccurred())
-
-	secretStore := &esv1alpha1.SecretStore{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      s.framework.Namespace.Name,
-			Namespace: s.framework.Namespace.Name,
-		},
-		Spec: esv1alpha1.SecretStoreSpec{
-			Provider: &esv1alpha1.SecretStoreProvider{
-				AWS: &esv1alpha1.AWSProvider{
-					Service: esv1alpha1.AWSServiceSecretsManager,
-					Region:  s.region,
-					Auth: esv1alpha1.AWSAuth{
-						SecretRef: &esv1alpha1.AWSAuthSecretRef{
-							AccessKeyID: esmetav1.SecretKeySelector{
-								Name: staticCredentialsSecretName,
-								Key:  "kid",
-							},
-							SecretAccessKey: esmetav1.SecretKeySelector{
-								Name: staticCredentialsSecretName,
-								Key:  "sak",
-							},
-						},
-					},
-				},
-			},
-		},
-	}
-	err = s.framework.CRClient.Create(context.Background(), secretStore)
-	Expect(err).ToNot(HaveOccurred())
-}

+ 0 - 0
e2e/suite/aws/secretsmanager.go → e2e/suite/aws/secretsmanager/secretsmanager.go


+ 85 - 0
e2e/suite/aws/secretsmanager/secretsmanager_managed.go

@@ -0,0 +1,85 @@
+/*
+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
+
+    http://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 aws
+
+import (
+
+	// nolint
+	. "github.com/onsi/ginkgo/v2"
+
+	"github.com/external-secrets/external-secrets/e2e/framework"
+	"github.com/external-secrets/external-secrets/e2e/framework/addon"
+	awscommon "github.com/external-secrets/external-secrets/e2e/suite/aws"
+	"github.com/external-secrets/external-secrets/e2e/suite/common"
+)
+
+// here we use the global eso instance
+// that uses the service account in the default namespace
+// which was created by terraform.
+var _ = Describe("[awsmanaged] IRSA via referenced service account", Label("aws", "secretsmanager", "managed"), func() {
+	f := framework.New("eso-aws-managed")
+	prov := NewFromEnv(f)
+
+	// nolint
+	DescribeTable("sync secretsmanager secrets",
+		framework.TableFunc(f,
+			prov),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.SimpleDataSync, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.NestedJSONWithGJSON, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataFromSync, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataWithProperty, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataWithTemplate, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.DockerJSONConfig, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.DataPropertyDockerconfigJSON, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.SSHKeySync, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.SSHKeySyncDataProperty, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.SyncWithoutTargetName, awscommon.UseClusterSecretStore),
+		framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataWithoutTargetName, awscommon.UseClusterSecretStore),
+	)
+})
+
+// here we create a central eso instance in the default namespace
+// that mounts the service account which was created by terraform.
+var _ = Describe("[awsmanaged] with mounted IRSA", Label("aws", "secretsmanager", "managed"), func() {
+	f := framework.New("eso-aws-managed")
+	prov := NewFromEnv(f)
+
+	// each test case gets its own ESO instance
+	BeforeEach(func() {
+		f.Install(addon.NewESO(
+			addon.WithControllerClass(f.BaseName),
+			addon.WithServiceAccount(prov.ServiceAccountName),
+			addon.WithReleaseName(f.Namespace.Name),
+			addon.WithNamespace("default"),
+		))
+	})
+
+	// nolint
+	DescribeTable("sync secretsmanager secrets",
+		framework.TableFunc(f,
+			prov),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.SimpleDataSync, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.NestedJSONWithGJSON, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataFromSync, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataWithProperty, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataWithTemplate, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.DockerJSONConfig, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.DataPropertyDockerconfigJSON, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.SSHKeySync, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.SSHKeySyncDataProperty, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.SyncWithoutTargetName, awscommon.UseMountedIRSAStore),
+		framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataWithoutTargetName, awscommon.UseMountedIRSAStore),
+	)
+})

+ 0 - 102
e2e/suite/aws/secretsmanager_managed.go

@@ -1,102 +0,0 @@
-/*
-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
-
-    http://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 aws
-
-import (
-
-	// nolint
-	. "github.com/onsi/ginkgo/v2"
-
-	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
-	"github.com/external-secrets/external-secrets/e2e/framework"
-	"github.com/external-secrets/external-secrets/e2e/framework/addon"
-	"github.com/external-secrets/external-secrets/e2e/suite/common"
-)
-
-const (
-	withReferencedIRSA = "with referenced IRSA"
-	withMountedIRSA    = "with mounted IRSA"
-)
-
-// here we use the global eso instance
-// that uses the service account in the default namespace
-// which was created by terraform.
-var _ = Describe("[awsmanaged] IRSA via referenced service account", Label("aws", "secretsmanager", "managed"), func() {
-	f := framework.New("eso-aws-managed")
-	prov := NewFromEnv(f)
-
-	DescribeTable("sync secrets",
-		framework.TableFunc(f,
-			prov),
-		framework.Compose(withReferencedIRSA, f, common.SimpleDataSync, useClusterSecretStore(prov)),
-		framework.Compose(withReferencedIRSA, f, common.NestedJSONWithGJSON, useClusterSecretStore(prov)),
-		framework.Compose(withReferencedIRSA, f, common.JSONDataFromSync, useClusterSecretStore(prov)),
-		framework.Compose(withReferencedIRSA, f, common.JSONDataWithProperty, useClusterSecretStore(prov)),
-		framework.Compose(withReferencedIRSA, f, common.JSONDataWithTemplate, useClusterSecretStore(prov)),
-		framework.Compose(withReferencedIRSA, f, common.DockerJSONConfig, useClusterSecretStore(prov)),
-		framework.Compose(withReferencedIRSA, f, common.DataPropertyDockerconfigJSON, useClusterSecretStore(prov)),
-		framework.Compose(withReferencedIRSA, f, common.SSHKeySync, useClusterSecretStore(prov)),
-		framework.Compose(withReferencedIRSA, f, common.SSHKeySyncDataProperty, useClusterSecretStore(prov)),
-		framework.Compose(withReferencedIRSA, f, common.SyncWithoutTargetName, useClusterSecretStore(prov)),
-		framework.Compose(withReferencedIRSA, f, common.JSONDataWithoutTargetName, useClusterSecretStore(prov)),
-	)
-})
-
-// here we create a central eso instance in the default namespace
-// that mounts the service account which was created by terraform.
-var _ = Describe("[awsmanaged] with mounted IRSA", Label("aws", "secretsmanager", "managed"), func() {
-	f := framework.New("eso-aws-managed")
-	prov := NewFromEnv(f)
-
-	// each test case gets its own ESO instance
-	BeforeEach(func() {
-		f.Install(addon.NewESO(
-			addon.WithControllerClass(f.BaseName),
-			addon.WithServiceAccount(prov.ServiceAccountName),
-			addon.WithReleaseName(f.Namespace.Name),
-			addon.WithNamespace("default"),
-		))
-	})
-
-	DescribeTable("sync secrets",
-		framework.TableFunc(f,
-			prov),
-		framework.Compose(withMountedIRSA, f, common.SimpleDataSync, useMountedIRSAStore(prov)),
-		framework.Compose(withMountedIRSA, f, common.NestedJSONWithGJSON, useMountedIRSAStore(prov)),
-		framework.Compose(withMountedIRSA, f, common.JSONDataFromSync, useMountedIRSAStore(prov)),
-		framework.Compose(withMountedIRSA, f, common.JSONDataWithProperty, useMountedIRSAStore(prov)),
-		framework.Compose(withMountedIRSA, f, common.JSONDataWithTemplate, useMountedIRSAStore(prov)),
-		framework.Compose(withMountedIRSA, f, common.DockerJSONConfig, useMountedIRSAStore(prov)),
-		framework.Compose(withMountedIRSA, f, common.DataPropertyDockerconfigJSON, useMountedIRSAStore(prov)),
-		framework.Compose(withMountedIRSA, f, common.SSHKeySync, useMountedIRSAStore(prov)),
-		framework.Compose(withMountedIRSA, f, common.SSHKeySyncDataProperty, useMountedIRSAStore(prov)),
-		framework.Compose(withMountedIRSA, f, common.SyncWithoutTargetName, useMountedIRSAStore(prov)),
-		framework.Compose(withMountedIRSA, f, common.JSONDataWithoutTargetName, useMountedIRSAStore(prov)),
-	)
-})
-
-func useClusterSecretStore(prov *SMProvider) func(*framework.TestCase) {
-	return func(tc *framework.TestCase) {
-		tc.ExternalSecret.Spec.SecretStoreRef.Kind = esv1alpha1.ClusterSecretStoreKind
-		tc.ExternalSecret.Spec.SecretStoreRef.Name = prov.ReferencedIRSAStoreName()
-	}
-}
-
-func useMountedIRSAStore(prov *SMProvider) func(*framework.TestCase) {
-	return func(tc *framework.TestCase) {
-		tc.ExternalSecret.Spec.SecretStoreRef.Kind = esv1alpha1.SecretStoreKind
-		tc.ExternalSecret.Spec.SecretStoreRef.Name = prov.MountedIRSAStoreName()
-	}
-}

+ 66 - 0
e2e/suite/azure/azure_cert.go

@@ -0,0 +1,66 @@
+/*
+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
+
+    http://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.
+limitations under the License.
+*/
+package azure
+
+import (
+	"fmt"
+
+	// nolint
+	. "github.com/onsi/ginkgo/v2"
+	v1 "k8s.io/api/core/v1"
+
+	// nolint
+	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
+	"github.com/external-secrets/external-secrets/e2e/framework"
+)
+
+// azure keyvault type=cert should get a certificate from the api.
+var _ = Describe("[azure]", Label("azure", "keyvault", "cert"), func() {
+	f := framework.New("eso-azure-certtype")
+	prov := newFromEnv(f)
+	var certBytes []byte
+	var certName string
+
+	BeforeEach(func() {
+		certName = fmt.Sprintf("%s-%s", f.Namespace.Name, "certtest")
+		prov.CreateCertificate(certName)
+		certBytes = prov.GetCertificate(certName)
+	})
+
+	AfterEach(func() {
+		prov.DeleteCertificate(certName)
+	})
+
+	ff := framework.TableFunc(f, prov)
+	It("should sync keyvault objects with type=cert", func() {
+		ff(func(tc *framework.TestCase) {
+			secretKey := "azkv-cert"
+
+			tc.ExpectedSecret = &v1.Secret{
+				Type: v1.SecretTypeOpaque,
+				Data: map[string][]byte{
+					secretKey: certBytes,
+				},
+			}
+			tc.ExternalSecret.Spec.Data = []esv1alpha1.ExternalSecretData{
+				{
+					SecretKey: secretKey,
+					RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
+						Key: "cert/" + certName,
+					},
+				},
+			}
+		})
+	})
+
+})

+ 69 - 0
e2e/suite/azure/azure_key.go

@@ -0,0 +1,69 @@
+/*
+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
+
+    http://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.
+limitations under the License.
+*/
+package azure
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"github.com/Azure/azure-sdk-for-go/profiles/latest/keyvault/keyvault"
+
+	// nolint
+	. "github.com/onsi/ginkgo/v2"
+	v1 "k8s.io/api/core/v1"
+
+	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
+	"github.com/external-secrets/external-secrets/e2e/framework"
+)
+
+// azure keyvault type=key should retrieve a jwk from the api.
+var _ = Describe("[azure]", Label("azure", "keyvault", "key"), func() {
+	f := framework.New("eso-azure-keytype")
+	prov := newFromEnv(f)
+	var jwk *keyvault.JSONWebKey
+	var keyName string
+
+	BeforeEach(func() {
+		keyName = fmt.Sprintf("%s-%s", f.Namespace.Name, "keytest")
+		jwk = prov.CreateKey(keyName)
+	})
+
+	AfterEach(func() {
+		prov.DeleteKey(keyName)
+	})
+
+	ff := framework.TableFunc(f, prov)
+
+	It("should sync keyvault objects with type=key", func() {
+		ff(func(tc *framework.TestCase) {
+			secretKey := "azkv-key"
+			keyBytes, _ := json.Marshal(jwk)
+
+			tc.ExpectedSecret = &v1.Secret{
+				Type: v1.SecretTypeOpaque,
+				Data: map[string][]byte{
+					secretKey: keyBytes,
+				},
+			}
+			tc.ExternalSecret.Spec.Data = []esv1alpha1.ExternalSecretData{
+				{
+					SecretKey: secretKey,
+					RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
+						Key: "key/" + keyName,
+					},
+				},
+			}
+		})
+	})
+
+})

+ 2 - 1
e2e/suite/azure/azure.go → e2e/suite/azure/azure_secret.go

@@ -21,7 +21,8 @@ import (
 	"github.com/external-secrets/external-secrets/e2e/suite/common"
 	"github.com/external-secrets/external-secrets/e2e/suite/common"
 )
 )
 
 
-var _ = Describe("[azure]", Label("azure", "keyvault"), func() {
+// keyvault type=secret should behave just like any other secret store.
+var _ = Describe("[azure]", Label("azure", "keyvault", "secret"), func() {
 	f := framework.New("eso-azure")
 	f := framework.New("eso-azure")
 	prov := newFromEnv(f)
 	prov := newFromEnv(f)
 
 

+ 80 - 4
e2e/suite/azure/provider.go

@@ -15,16 +15,15 @@ package azure
 import (
 import (
 	"context"
 	"context"
 	"os"
 	"os"
+	"time"
 
 
 	"github.com/Azure/azure-sdk-for-go/profiles/latest/keyvault/keyvault"
 	"github.com/Azure/azure-sdk-for-go/profiles/latest/keyvault/keyvault"
 	kvauth "github.com/Azure/go-autorest/autorest/azure/auth"
 	kvauth "github.com/Azure/go-autorest/autorest/azure/auth"
 
 
-	// nolint
-	. "github.com/onsi/gomega"
-
 	// nolint
 	// nolint
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/ginkgo/v2"
-
+	// nolint
+	. "github.com/onsi/gomega"
 	v1 "k8s.io/api/core/v1"
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	utilpointer "k8s.io/utils/pointer"
 	utilpointer "k8s.io/utils/pointer"
@@ -100,6 +99,83 @@ func (s *azureProvider) DeleteSecret(key string) {
 	Expect(err).ToNot(HaveOccurred())
 	Expect(err).ToNot(HaveOccurred())
 }
 }
 
 
+func (s *azureProvider) CreateKey(key string) *keyvault.JSONWebKey {
+	out, err := s.client.CreateKey(
+		context.Background(),
+		s.vaultURL,
+		key,
+		keyvault.KeyCreateParameters{
+			Kty: keyvault.RSA,
+			KeyAttributes: &keyvault.KeyAttributes{
+				RecoveryLevel: keyvault.Purgeable,
+				Enabled:       utilpointer.BoolPtr(true),
+			},
+		},
+	)
+	Expect(err).ToNot(HaveOccurred())
+	return out.Key
+}
+
+func (s *azureProvider) DeleteKey(key string) {
+	_, err := s.client.DeleteKey(context.Background(), s.vaultURL, key)
+	Expect(err).ToNot(HaveOccurred())
+}
+
+func (s *azureProvider) CreateCertificate(key string) {
+	_, err := s.client.CreateCertificate(
+		context.Background(),
+		s.vaultURL,
+		key,
+		keyvault.CertificateCreateParameters{
+			CertificatePolicy: &keyvault.CertificatePolicy{
+				X509CertificateProperties: &keyvault.X509CertificateProperties{
+					Subject:          utilpointer.String("CN=e2e.test"),
+					ValidityInMonths: utilpointer.Int32(42),
+				},
+				IssuerParameters: &keyvault.IssuerParameters{
+					Name: utilpointer.String("Self"),
+				},
+				Attributes: &keyvault.CertificateAttributes{
+					RecoveryLevel: keyvault.Purgeable,
+					Enabled:       utilpointer.BoolPtr(true),
+				},
+			},
+			CertificateAttributes: &keyvault.CertificateAttributes{
+				RecoveryLevel: keyvault.Purgeable,
+				Enabled:       utilpointer.BoolPtr(true),
+			},
+		},
+	)
+	Expect(err).ToNot(HaveOccurred())
+}
+
+func (s *azureProvider) GetCertificate(key string) []byte {
+	attempts := 20
+	for {
+		out, err := s.client.GetCertificate(
+			context.Background(),
+			s.vaultURL,
+			key,
+			"",
+		)
+		Expect(err).ToNot(HaveOccurred())
+		if out.Cer != nil {
+			return *out.Cer
+		}
+
+		attempts--
+		if attempts <= 0 {
+			Fail("failed fetching azkv certificate")
+		}
+		<-time.After(time.Second * 5)
+	}
+}
+
+func (s *azureProvider) DeleteCertificate(key string) {
+	_, err := s.client.DeleteCertificate(context.Background(), s.vaultURL, key)
+	Expect(err).ToNot(HaveOccurred())
+}
+
 func (s *azureProvider) CreateSecretStore() {
 func (s *azureProvider) CreateSecretStore() {
 	azureCreds := &v1.Secret{
 	azureCreds := &v1.Secret{
 		ObjectMeta: metav1.ObjectMeta{
 		ObjectMeta: metav1.ObjectMeta{

+ 2 - 1
e2e/suite/import.go

@@ -16,7 +16,8 @@ package suite
 import (
 import (
 
 
 	// import different e2e test suites.
 	// import different e2e test suites.
-	_ "github.com/external-secrets/external-secrets/e2e/suite/aws"
+	_ "github.com/external-secrets/external-secrets/e2e/suite/aws/parameterstore"
+	_ "github.com/external-secrets/external-secrets/e2e/suite/aws/secretsmanager"
 	_ "github.com/external-secrets/external-secrets/e2e/suite/azure"
 	_ "github.com/external-secrets/external-secrets/e2e/suite/azure"
 	_ "github.com/external-secrets/external-secrets/e2e/suite/gcp"
 	_ "github.com/external-secrets/external-secrets/e2e/suite/gcp"
 	_ "github.com/external-secrets/external-secrets/e2e/suite/vault"
 	_ "github.com/external-secrets/external-secrets/e2e/suite/vault"

+ 11 - 18
go.mod

@@ -33,7 +33,7 @@ replace (
 )
 )
 
 
 require (
 require (
-	cloud.google.com/go v0.99.0
+	cloud.google.com/go v0.100.2 // indirect
 	cloud.google.com/go/secretmanager v1.0.0
 	cloud.google.com/go/secretmanager v1.0.0
 	github.com/Azure/azure-sdk-for-go v61.1.0+incompatible
 	github.com/Azure/azure-sdk-for-go v61.1.0+incompatible
 	github.com/Azure/go-autorest/autorest/azure/auth v0.5.7
 	github.com/Azure/go-autorest/autorest/azure/auth v0.5.7
@@ -45,33 +45,33 @@ require (
 	github.com/PaesslerAG/jsonpath v0.1.1
 	github.com/PaesslerAG/jsonpath v0.1.1
 	github.com/ahmetb/gen-crd-api-reference-docs v0.3.0
 	github.com/ahmetb/gen-crd-api-reference-docs v0.3.0
 	github.com/akeylesslabs/akeyless-go-cloud-id v0.3.2
 	github.com/akeylesslabs/akeyless-go-cloud-id v0.3.2
-	github.com/akeylesslabs/akeyless-go/v2 v2.15.24
-	github.com/aliyun/alibaba-cloud-sdk-go v1.61.1458
+	github.com/akeylesslabs/akeyless-go/v2 v2.15.25
+	github.com/aliyun/alibaba-cloud-sdk-go v1.61.1473
 	github.com/aws/aws-sdk-go v1.38.6
 	github.com/aws/aws-sdk-go v1.38.6
 	github.com/crossplane/crossplane-runtime v0.15.1
 	github.com/crossplane/crossplane-runtime v0.15.1
 	github.com/go-logr/logr v1.2.2
 	github.com/go-logr/logr v1.2.2
 	github.com/golang-jwt/jwt/v4 v4.2.0
 	github.com/golang-jwt/jwt/v4 v4.2.0
 	github.com/google/go-cmp v0.5.7
 	github.com/google/go-cmp v0.5.7
 	github.com/google/uuid v1.2.0
 	github.com/google/uuid v1.2.0
-	github.com/googleapis/gax-go v1.0.3
+	github.com/googleapis/gax-go/v2 v2.1.1
 	github.com/hashicorp/vault/api v1.3.1
 	github.com/hashicorp/vault/api v1.3.1
 	github.com/huandu/xstrings v1.3.2 // indirect
 	github.com/huandu/xstrings v1.3.2 // indirect
 	github.com/lestrrat-go/jwx v1.2.1
 	github.com/lestrrat-go/jwx v1.2.1
-	github.com/onsi/ginkgo/v2 v2.0.0
+	github.com/onsi/ginkgo/v2 v2.1.1
 	github.com/onsi/gomega v1.17.0
 	github.com/onsi/gomega v1.17.0
 	github.com/oracle/oci-go-sdk/v45 v45.2.0
 	github.com/oracle/oci-go-sdk/v45 v45.2.0
 	github.com/prometheus/client_golang v1.11.0
 	github.com/prometheus/client_golang v1.11.0
 	github.com/prometheus/client_model v0.2.0
 	github.com/prometheus/client_model v0.2.0
 	github.com/stretchr/testify v1.7.0
 	github.com/stretchr/testify v1.7.0
 	github.com/tidwall/gjson v1.12.1
 	github.com/tidwall/gjson v1.12.1
-	github.com/xanzy/go-gitlab v0.50.1
+	github.com/xanzy/go-gitlab v0.54.3
 	github.com/yandex-cloud/go-genproto v0.0.0-20210809082946-a97da516c588
 	github.com/yandex-cloud/go-genproto v0.0.0-20210809082946-a97da516c588
 	github.com/yandex-cloud/go-sdk v0.0.0-20210809100642-c13c40a429fa
 	github.com/yandex-cloud/go-sdk v0.0.0-20210809100642-c13c40a429fa
 	github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a
 	github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a
 	go.uber.org/zap v1.20.0
 	go.uber.org/zap v1.20.0
 	golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce
 	golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce
 	golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
 	golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
-	google.golang.org/api v0.61.0
+	google.golang.org/api v0.64.0
 	google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5
 	google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5
 	google.golang.org/grpc v1.43.0
 	google.golang.org/grpc v1.43.0
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
@@ -85,7 +85,10 @@ require (
 	software.sslmate.com/src/go-pkcs12 v0.0.0-20210415151418-c5206de65a78
 	software.sslmate.com/src/go-pkcs12 v0.0.0-20210415151418-c5206de65a78
 )
 )
 
 
+require cloud.google.com/go/iam v0.1.1
+
 require (
 require (
+	cloud.google.com/go/compute v0.1.0 // indirect
 	github.com/Azure/go-autorest v14.2.0+incompatible // indirect
 	github.com/Azure/go-autorest v14.2.0+incompatible // indirect
 	github.com/Azure/go-autorest/autorest v0.11.18 // indirect
 	github.com/Azure/go-autorest/autorest v0.11.18 // indirect
 	github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect
 	github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect
@@ -95,7 +98,6 @@ require (
 	github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
 	github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
 	github.com/Azure/go-autorest/logger v0.2.1 // indirect
 	github.com/Azure/go-autorest/logger v0.2.1 // indirect
 	github.com/Azure/go-autorest/tracing v0.6.0 // indirect
 	github.com/Azure/go-autorest/tracing v0.6.0 // indirect
-	github.com/BurntSushi/toml v0.3.1 // indirect
 	github.com/PaesslerAG/gval v1.0.0 // indirect
 	github.com/PaesslerAG/gval v1.0.0 // indirect
 	github.com/armon/go-metrics v0.3.10 // indirect
 	github.com/armon/go-metrics v0.3.10 // indirect
 	github.com/armon/go-radix v1.0.0 // indirect
 	github.com/armon/go-radix v1.0.0 // indirect
@@ -103,16 +105,11 @@ require (
 	github.com/aws/aws-sdk-go-v2 v0.23.0 // indirect
 	github.com/aws/aws-sdk-go-v2 v0.23.0 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/cenkalti/backoff/v3 v3.2.2 // indirect
 	github.com/cenkalti/backoff/v3 v3.2.2 // indirect
-	github.com/census-instrumentation/opencensus-proto v0.2.1 // indirect
 	github.com/cespare/xxhash/v2 v2.1.1 // indirect
 	github.com/cespare/xxhash/v2 v2.1.1 // indirect
-	github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect
-	github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0 // indirect
 	github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0 // indirect
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
 	github.com/dimchansky/utfbom v1.1.1 // indirect
 	github.com/dimchansky/utfbom v1.1.1 // indirect
-	github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021 // indirect
-	github.com/envoyproxy/protoc-gen-validate v0.1.0 // indirect
 	github.com/evanphx/json-patch v4.12.0+incompatible // indirect
 	github.com/evanphx/json-patch v4.12.0+incompatible // indirect
 	github.com/fatih/color v1.13.0 // indirect
 	github.com/fatih/color v1.13.0 // indirect
 	github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
 	github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
@@ -131,10 +128,9 @@ require (
 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/golang/snappy v0.0.4 // indirect
 	github.com/golang/snappy v0.0.4 // indirect
-	github.com/google/go-querystring v1.0.0 // indirect
+	github.com/google/go-querystring v1.1.0 // indirect
 	github.com/google/gofuzz v1.2.0 // indirect
 	github.com/google/gofuzz v1.2.0 // indirect
 	github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
 	github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
-	github.com/googleapis/gax-go/v2 v2.1.1 // indirect
 	github.com/googleapis/gnostic v0.5.5 // indirect
 	github.com/googleapis/gnostic v0.5.5 // indirect
 	github.com/hashicorp/errwrap v1.1.0 // indirect
 	github.com/hashicorp/errwrap v1.1.0 // indirect
 	github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
 	github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
@@ -194,8 +190,6 @@ require (
 	go.opencensus.io v0.23.0 // indirect
 	go.opencensus.io v0.23.0 // indirect
 	go.uber.org/atomic v1.9.0 // indirect
 	go.uber.org/atomic v1.9.0 // indirect
 	go.uber.org/multierr v1.6.0 // indirect
 	go.uber.org/multierr v1.6.0 // indirect
-	golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 // indirect
-	golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
 	golang.org/x/mod v0.4.2 // indirect
 	golang.org/x/mod v0.4.2 // indirect
 	golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d // indirect
 	golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d // indirect
 	golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
 	golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
@@ -212,7 +206,6 @@ require (
 	gopkg.in/ini.v1 v1.66.2 // indirect
 	gopkg.in/ini.v1 v1.66.2 // indirect
 	gopkg.in/square/go-jose.v2 v2.6.0 // indirect
 	gopkg.in/square/go-jose.v2 v2.6.0 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
-	honnef.co/go/tools v0.1.4 // indirect
 	k8s.io/apiextensions-apiserver v0.23.0 // indirect
 	k8s.io/apiextensions-apiserver v0.23.0 // indirect
 	k8s.io/component-base v0.23.0 // indirect
 	k8s.io/component-base v0.23.0 // indirect
 	k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c // indirect
 	k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c // indirect

+ 27 - 32
go.sum

@@ -25,17 +25,23 @@ cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aD
 cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
 cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
 cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
 cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
 cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
 cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
-cloud.google.com/go v0.99.0 h1:y/cM2iqGgGi5D5DQZl6D9STN/3dR/Vx5Mp8s752oJTY=
 cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
 cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
+cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U=
+cloud.google.com/go v0.100.2 h1:t9Iw5QH5v4XtlEQaCtUY7x6sCABps8sW0acw7e2WQ6Y=
+cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
 cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
 cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
 cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
 cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
 cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
 cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
 cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
 cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
 cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
 cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
 cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
 cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
+cloud.google.com/go/compute v0.1.0 h1:rSUBvAyVwNJ5uQCKNJFMwPtTvJkfN38b6Pvb9zZoqJ8=
+cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
 cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
 cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
 cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
 cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+cloud.google.com/go/iam v0.1.1 h1:4CapQyNFjiksks1/x7jsvsygFPhihslYk5GptIrlX68=
+cloud.google.com/go/iam v0.1.1/go.mod h1:CKqrcnI/suGpybEHxZ7BMehL0oA4LpdyJdUlTl9jVMw=
 cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
 cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
 cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
 cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
 cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
 cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@@ -78,7 +84,6 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z
 github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
 github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
 github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
 github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
 github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
 github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
-github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
 github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
@@ -107,15 +112,15 @@ github.com/ahmetb/gen-crd-api-reference-docs v0.3.0 h1:+XfOU14S4bGuwyvCijJwhhBIj
 github.com/ahmetb/gen-crd-api-reference-docs v0.3.0/go.mod h1:TdjdkYhlOifCQWPs1UdTma97kQQMozf5h26hTuG70u8=
 github.com/ahmetb/gen-crd-api-reference-docs v0.3.0/go.mod h1:TdjdkYhlOifCQWPs1UdTma97kQQMozf5h26hTuG70u8=
 github.com/akeylesslabs/akeyless-go-cloud-id v0.3.2 h1:1h4udX3Y5KgSG0m4Th2bHfaYxZB9fbngiij9PrKEp6c=
 github.com/akeylesslabs/akeyless-go-cloud-id v0.3.2 h1:1h4udX3Y5KgSG0m4Th2bHfaYxZB9fbngiij9PrKEp6c=
 github.com/akeylesslabs/akeyless-go-cloud-id v0.3.2/go.mod h1:ionnWiARf5TYoFGuHS7syh51/7lYosZejpZbnECFJcU=
 github.com/akeylesslabs/akeyless-go-cloud-id v0.3.2/go.mod h1:ionnWiARf5TYoFGuHS7syh51/7lYosZejpZbnECFJcU=
-github.com/akeylesslabs/akeyless-go/v2 v2.15.24 h1:q++f8n4l66kSptlo9cxrYq8fGHg25GdjqOsw0vbKUAE=
-github.com/akeylesslabs/akeyless-go/v2 v2.15.24/go.mod h1:uOdXD49NCCe4rexeSc2aBU5Qv4KZgJE6YlbtYalvb+I=
+github.com/akeylesslabs/akeyless-go/v2 v2.15.25 h1:9iztd2fXVfj4b3LRsyvGNRheFoz8IFs/+K4GaAshZc4=
+github.com/akeylesslabs/akeyless-go/v2 v2.15.25/go.mod h1:uOdXD49NCCe4rexeSc2aBU5Qv4KZgJE6YlbtYalvb+I=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
-github.com/aliyun/alibaba-cloud-sdk-go v1.61.1458 h1:pMdm+s6k9yeAYJNqgZIpZcDBuh2SNR3Q137G9rpxDZc=
-github.com/aliyun/alibaba-cloud-sdk-go v1.61.1458/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
+github.com/aliyun/alibaba-cloud-sdk-go v1.61.1473 h1:rUoiu7Duq0hr4mjlQWZMORKaCbNXaYvYN2HFJQt228E=
+github.com/aliyun/alibaba-cloud-sdk-go v1.61.1473/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
 github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@@ -152,7 +157,6 @@ github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9cop
 github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
 github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
 github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M=
 github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M=
 github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
 github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
-github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
 github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
 github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
 github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
@@ -170,12 +174,10 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
 github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 h1:hzAQntlaYRkVSFEfj9OTWlVV1H155FMD8BTKktLv0QI=
 github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
 github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
 github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1 h1:zH8ljVhhq7yC0MIeUL/IviMtY8hx2mK8cN9wEYb8ggw=
 github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
 github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
 github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
 github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
@@ -222,9 +224,7 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y
 github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
 github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
 github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
 github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
 github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
 github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
-github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021 h1:fP+fF0up6oPY49OrjPrhIJ8yQfdIM85NXMLkMg1EXVs=
 github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
 github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
-github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
 github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
 github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
@@ -340,7 +340,6 @@ github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4er
 github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
 github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
@@ -391,8 +390,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
 github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
 github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
 github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
-github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
-github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
+github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
 github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
@@ -422,9 +421,6 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
 github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
 github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/gax-go v1.0.3 h1:9dMLqhaibYONnDRcnHdUs9P8Mw64jLlZTYlDe3leBtQ=
-github.com/googleapis/gax-go v1.0.3/go.mod h1:QyXYajJFdARxGzjwUfbDFIse7Spkw81SJ4LrBJXtlQ8=
-github.com/googleapis/gax-go/v2 v2.0.2/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
 github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
@@ -682,8 +678,8 @@ github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvw
 github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
 github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
 github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
 github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
 github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
 github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
-github.com/onsi/ginkgo/v2 v2.0.0 h1:CcuG/HvWNkkaqCUpJifQY8z7qEMBJya6aLPx6ftGyjQ=
-github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
+github.com/onsi/ginkgo/v2 v2.1.1 h1:LCnPB85AvFNr91s0B2aDzEiiIg6MUwLYbryC1NSlWi8=
+github.com/onsi/ginkgo/v2 v2.1.1/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
 github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
 github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
 github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
@@ -814,8 +810,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1
 github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
 github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
 github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
 github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
-github.com/xanzy/go-gitlab v0.50.1 h1:eH1G0/ZV1j81rhGrtbcePjbM5Ern7mPA4Xjt+yE+2PQ=
-github.com/xanzy/go-gitlab v0.50.1/go.mod h1:Q+hQhV508bDPoBijv7YjK/Lvlb4PhVhJdKqXVQrUoAE=
+github.com/xanzy/go-gitlab v0.54.3 h1:fPfZ3Jcu5dPc3xyIYtAALZsEgoyKNFNuULD+TdJ7Zvk=
+github.com/xanzy/go-gitlab v0.54.3/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM=
 github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
 github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
 github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
 github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
 github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
 github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
@@ -904,7 +900,6 @@ golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5y
 golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce h1:Roh6XWxHFKrPgC/EQhVubSAGQ6Ozk6IdxHSzt1mR0EI=
 golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce h1:Roh6XWxHFKrPgC/EQhVubSAGQ6Ozk6IdxHSzt1mR0EI=
 golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190221220918-438050ddec5e/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
 golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
 golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
@@ -914,11 +909,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 h1:FR+oGxGfbQu1d+jglI3rCkjAjUnhRSZcUxr+DqlDLNo=
-golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -930,7 +922,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu
 golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
@@ -1109,6 +1100,8 @@ golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
 golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
 golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
@@ -1135,7 +1128,6 @@ golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxb
 golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
 golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
 golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -1243,8 +1235,10 @@ google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6
 google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
 google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
 google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
 google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
 google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
 google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
-google.golang.org/api v0.61.0 h1:TXXKS1slM3b2bZNJwD5DV/Tp6/M2cLzLOLh9PjDhrw8=
 google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
 google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
+google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
+google.golang.org/api v0.64.0 h1:l3pi8ncrQgB9+ncFw3A716L8lWujnXniBYbxWqqy6tE=
+google.golang.org/api v0.64.0/go.mod h1:931CdxA8Rm4t6zqTFGSsgwbAEZ2+GMYurbndwSimebM=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -1319,10 +1313,13 @@ google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6/go.mod h1:5CzLGKJ6
 google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20220111164026-67b88f271998/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5 h1:zzNejm+EgrbLfDZ6lu9Uud2IVvHySPl8vQzf04laR5Q=
 google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5 h1:zzNejm+EgrbLfDZ6lu9Uud2IVvHySPl8vQzf04laR5Q=
 google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
 google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -1348,6 +1345,7 @@ google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ
 google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
 google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
 google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
 google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
 google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
 google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
+google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
 google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
 google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
 google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM=
 google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM=
 google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
 google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
@@ -1413,7 +1411,6 @@ gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
 gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
 gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
 grpc.go4.org v0.0.0-20170609214715-11d0a25b4919 h1:tmXTu+dfa+d9Evp8NpJdgOy6+rt8/x4yG7qPBrtNfLY=
 grpc.go4.org v0.0.0-20170609214715-11d0a25b4919 h1:tmXTu+dfa+d9Evp8NpJdgOy6+rt8/x4yG7qPBrtNfLY=
 grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
 grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
-honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -1421,8 +1418,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
 honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-honnef.co/go/tools v0.1.4 h1:SadWOkti5uVN1FAMgxn165+Mw00fuQKyk4Gyn/inxNQ=
-honnef.co/go/tools v0.1.4/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
 k8s.io/api v0.23.0 h1:WrL1gb73VSC8obi8cuYETJGXEoFNEh3LU0Pt+Sokgro=
 k8s.io/api v0.23.0 h1:WrL1gb73VSC8obi8cuYETJGXEoFNEh3LU0Pt+Sokgro=
 k8s.io/api v0.23.0/go.mod h1:8wmDdLBHBNxtOIytwLstXt5E9PddnZb0GaMcqsvDBpg=
 k8s.io/api v0.23.0/go.mod h1:8wmDdLBHBNxtOIytwLstXt5E9PddnZb0GaMcqsvDBpg=
 k8s.io/apiextensions-apiserver v0.23.0 h1:uii8BYmHYiT2ZTAJxmvc3X8UhNYMxl2A0z0Xq3Pm+WY=
 k8s.io/apiextensions-apiserver v0.23.0 h1:uii8BYmHYiT2ZTAJxmvc3X8UhNYMxl2A0z0Xq3Pm+WY=

+ 1 - 0
hack/api-docs/mkdocs.yml

@@ -61,6 +61,7 @@ nav:
     - Oracle:
     - Oracle:
       - Oracle Vault: provider-oracle-vault.md
       - Oracle Vault: provider-oracle-vault.md
     - Webhook: provider-webhook.md
     - Webhook: provider-webhook.md
+    - Fake: provider-fake.md
   - References:
   - References:
     - API specification: spec.md
     - API specification: spec.md
   - Contributing:
   - Contributing:

+ 1 - 3
pkg/controllers/externalsecret/externalsecret_controller_template.go

@@ -64,9 +64,7 @@ func (r *Reconciler) applyTemplate(ctx context.Context, es *esv1alpha1.ExternalS
 	// if no data was provided by template fallback
 	// if no data was provided by template fallback
 	// to value from the provider
 	// to value from the provider
 	if len(es.Spec.Target.Template.Data) == 0 {
 	if len(es.Spec.Target.Template.Data) == 0 {
-		for k, v := range dataMap {
-			secret.Data[k] = v
-		}
+		secret.Data = dataMap
 	}
 	}
 	secret.Annotations[esv1alpha1.AnnotationDataHash] = utils.ObjectHash(secret.Data)
 	secret.Annotations[esv1alpha1.AnnotationDataHash] = utils.ObjectHash(secret.Data)
 
 

+ 82 - 1
pkg/controllers/externalsecret/externalsecret_controller_test.go

@@ -31,8 +31,8 @@ import (
 
 
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
 	"github.com/external-secrets/external-secrets/pkg/provider"
 	"github.com/external-secrets/external-secrets/pkg/provider"
-	"github.com/external-secrets/external-secrets/pkg/provider/fake"
 	"github.com/external-secrets/external-secrets/pkg/provider/schema"
 	"github.com/external-secrets/external-secrets/pkg/provider/schema"
+	"github.com/external-secrets/external-secrets/pkg/provider/testing/fake"
 )
 )
 
 
 var (
 var (
@@ -654,6 +654,85 @@ var _ = Describe("ExternalSecret controller", func() {
 		}
 		}
 	}
 	}
 
 
+	// when a provider secret was deleted it must be deleted from
+	// the secret aswell
+	refreshSecretValueMap := func(tc *testCase) {
+		fakeProvider.WithGetSecretMap(map[string][]byte{
+			"foo": []byte("1111"),
+			"bar": []byte("2222"),
+		}, nil)
+		tc.externalSecret.Spec.Data = []esv1alpha1.ExternalSecretData{}
+		tc.externalSecret.Spec.DataFrom = []esv1alpha1.ExternalSecretDataRemoteRef{
+			{
+				Key: remoteKey,
+			},
+		}
+		tc.externalSecret.Spec.RefreshInterval = &metav1.Duration{Duration: time.Second}
+		tc.checkSecret = func(es *esv1alpha1.ExternalSecret, secret *v1.Secret) {
+			// check values
+			Expect(string(secret.Data["foo"])).To(Equal("1111"))
+			Expect(string(secret.Data["bar"])).To(Equal("2222"))
+
+			// update provider secret
+			sec := &v1.Secret{}
+			fakeProvider.WithGetSecretMap(map[string][]byte{
+				"foo": []byte("1111"),
+			}, nil)
+			secretLookupKey := types.NamespacedName{
+				Name:      ExternalSecretTargetSecretName,
+				Namespace: ExternalSecretNamespace,
+			}
+			Eventually(func() bool {
+				err := k8sClient.Get(context.Background(), secretLookupKey, sec)
+				if err != nil {
+					return false
+				}
+				return string(sec.Data["foo"]) == "1111" &&
+					sec.Data["bar"] == nil // must not be defined, it was deleted
+			}, timeout, interval).Should(BeTrue())
+		}
+	}
+
+	// when a provider secret was deleted it must be deleted from
+	// the secret aswell when using a template
+	refreshSecretValueMapTemplate := func(tc *testCase) {
+		fakeProvider.WithGetSecretMap(map[string][]byte{
+			"foo": []byte("1111"),
+			"bar": []byte("2222"),
+		}, nil)
+		tc.externalSecret.Spec.Target.Template = &esv1alpha1.ExternalSecretTemplate{}
+		tc.externalSecret.Spec.Data = []esv1alpha1.ExternalSecretData{}
+		tc.externalSecret.Spec.DataFrom = []esv1alpha1.ExternalSecretDataRemoteRef{
+			{
+				Key: remoteKey,
+			},
+		}
+		tc.externalSecret.Spec.RefreshInterval = &metav1.Duration{Duration: time.Second}
+		tc.checkSecret = func(es *esv1alpha1.ExternalSecret, secret *v1.Secret) {
+			// check values
+			Expect(string(secret.Data["foo"])).To(Equal("1111"))
+			Expect(string(secret.Data["bar"])).To(Equal("2222"))
+
+			// update provider secret
+			sec := &v1.Secret{}
+			fakeProvider.WithGetSecretMap(map[string][]byte{
+				"foo": []byte("1111"),
+			}, nil)
+			secretLookupKey := types.NamespacedName{
+				Name:      ExternalSecretTargetSecretName,
+				Namespace: ExternalSecretNamespace,
+			}
+			Eventually(func() bool {
+				err := k8sClient.Get(context.Background(), secretLookupKey, sec)
+				if err != nil {
+					return false
+				}
+				return string(sec.Data["foo"]) == "1111" &&
+					sec.Data["bar"] == nil // must not be defined, it was deleted
+			}, timeout, interval).Should(BeTrue())
+		}
+	}
+
 	refreshintervalZero := func(tc *testCase) {
 	refreshintervalZero := func(tc *testCase) {
 		const targetProp = "targetProperty"
 		const targetProp = "targetProperty"
 		const secretVal = "someValue"
 		const secretVal = "someValue"
@@ -971,6 +1050,8 @@ var _ = Describe("ExternalSecret controller", func() {
 		Entry("should refresh secret from template", refreshWithTemplate),
 		Entry("should refresh secret from template", refreshWithTemplate),
 		Entry("should be able to use only metadata from template", onlyMetadataFromTemplate),
 		Entry("should be able to use only metadata from template", onlyMetadataFromTemplate),
 		Entry("should refresh secret value when provider secret changes", refreshSecretValue),
 		Entry("should refresh secret value when provider secret changes", refreshSecretValue),
+		Entry("should refresh secret map when provider secret changes", refreshSecretValueMap),
+		Entry("should refresh secret map when provider secret changes when using a template", refreshSecretValueMapTemplate),
 		Entry("should not refresh secret value when provider secret changes but refreshInterval is zero", refreshintervalZero),
 		Entry("should not refresh secret value when provider secret changes but refreshInterval is zero", refreshintervalZero),
 		Entry("should fetch secret using dataFrom", syncWithDataFrom),
 		Entry("should fetch secret using dataFrom", syncWithDataFrom),
 		Entry("should fetch secret using dataFrom and a template", syncWithDataFromTemplate),
 		Entry("should fetch secret using dataFrom and a template", syncWithDataFromTemplate),

+ 57 - 0
pkg/controllers/externalsecret/metrics.go

@@ -16,6 +16,7 @@ package externalsecret
 
 
 import (
 import (
 	"github.com/prometheus/client_golang/prometheus"
 	"github.com/prometheus/client_golang/prometheus"
+	v1 "k8s.io/api/core/v1"
 	"sigs.k8s.io/controller-runtime/pkg/metrics"
 	"sigs.k8s.io/controller-runtime/pkg/metrics"
 
 
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
@@ -50,6 +51,62 @@ var (
 
 
 // updateExternalSecretCondition updates the ExternalSecret conditions.
 // updateExternalSecretCondition updates the ExternalSecret conditions.
 func updateExternalSecretCondition(es *esv1alpha1.ExternalSecret, condition *esv1alpha1.ExternalSecretStatusCondition, value float64) {
 func updateExternalSecretCondition(es *esv1alpha1.ExternalSecret, condition *esv1alpha1.ExternalSecretStatusCondition, value float64) {
+	switch condition.Type {
+	case esv1alpha1.ExternalSecretDeleted:
+		// Remove condition=Ready metrics when the object gets deleted.
+		externalSecretCondition.Delete(prometheus.Labels{
+			"name":      es.Name,
+			"namespace": es.Namespace,
+			"condition": string(esv1alpha1.ExternalSecretReady),
+			"status":    string(v1.ConditionFalse),
+		})
+		externalSecretCondition.Delete(prometheus.Labels{
+			"name":      es.Name,
+			"namespace": es.Namespace,
+			"condition": string(esv1alpha1.ExternalSecretReady),
+			"status":    string(v1.ConditionTrue),
+		})
+
+	case esv1alpha1.ExternalSecretReady:
+		// Remove condition=Deleted metrics when the object gets ready.
+		externalSecretCondition.Delete(prometheus.Labels{
+			"name":      es.Name,
+			"namespace": es.Namespace,
+			"condition": string(esv1alpha1.ExternalSecretDeleted),
+			"status":    string(v1.ConditionFalse),
+		})
+		externalSecretCondition.Delete(prometheus.Labels{
+			"name":      es.Name,
+			"namespace": es.Namespace,
+			"condition": string(esv1alpha1.ExternalSecretDeleted),
+			"status":    string(v1.ConditionTrue),
+		})
+		// Toggle opposite Status to 0
+		switch condition.Status {
+		case v1.ConditionFalse:
+			externalSecretCondition.With(prometheus.Labels{
+				"name":      es.Name,
+				"namespace": es.Namespace,
+				"condition": string(esv1alpha1.ExternalSecretReady),
+				"status":    string(v1.ConditionTrue),
+			}).Set(0)
+		case v1.ConditionTrue:
+			externalSecretCondition.With(prometheus.Labels{
+				"name":      es.Name,
+				"namespace": es.Namespace,
+				"condition": string(esv1alpha1.ExternalSecretReady),
+				"status":    string(v1.ConditionFalse),
+			}).Set(0)
+		case v1.ConditionUnknown:
+			break
+		default:
+			break
+		}
+
+	default:
+		break
+	}
+
 	externalSecretCondition.With(prometheus.Labels{
 	externalSecretCondition.With(prometheus.Labels{
 		"name":      es.Name,
 		"name":      es.Name,
 		"namespace": es.Namespace,
 		"namespace": es.Namespace,

+ 7 - 1
pkg/controllers/externalsecret/suite_test.go

@@ -15,6 +15,7 @@ limitations under the License.
 package externalsecret
 package externalsecret
 
 
 import (
 import (
+	"context"
 	"path/filepath"
 	"path/filepath"
 	"testing"
 	"testing"
 	"time"
 	"time"
@@ -40,6 +41,7 @@ import (
 var cfg *rest.Config
 var cfg *rest.Config
 var k8sClient client.Client
 var k8sClient client.Client
 var testEnv *envtest.Environment
 var testEnv *envtest.Environment
+var cancel context.CancelFunc
 
 
 func TestAPIs(t *testing.T) {
 func TestAPIs(t *testing.T) {
 	RegisterFailHandler(Fail)
 	RegisterFailHandler(Fail)
@@ -56,6 +58,9 @@ var _ = BeforeSuite(func() {
 		CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "deploy", "crds")},
 		CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "deploy", "crds")},
 	}
 	}
 
 
+	var ctx context.Context
+	ctx, cancel = context.WithCancel(context.Background())
+
 	var err error
 	var err error
 	cfg, err = testEnv.Start()
 	cfg, err = testEnv.Start()
 	Expect(err).ToNot(HaveOccurred())
 	Expect(err).ToNot(HaveOccurred())
@@ -87,12 +92,13 @@ var _ = BeforeSuite(func() {
 
 
 	go func() {
 	go func() {
 		defer GinkgoRecover()
 		defer GinkgoRecover()
-		Expect(k8sManager.Start(ctrl.SetupSignalHandler())).ToNot(HaveOccurred())
+		Expect(k8sManager.Start(ctx)).ToNot(HaveOccurred())
 	}()
 	}()
 })
 })
 
 
 var _ = AfterSuite(func() {
 var _ = AfterSuite(func() {
 	By("tearing down the test environment")
 	By("tearing down the test environment")
+	cancel() // stop manager
 	err := testEnv.Stop()
 	err := testEnv.Stop()
 	Expect(err).ToNot(HaveOccurred())
 	Expect(err).ToNot(HaveOccurred())
 })
 })

+ 51 - 58
pkg/provider/fake/fake.go

@@ -16,6 +16,7 @@ package fake
 
 
 import (
 import (
 	"context"
 	"context"
+	"fmt"
 
 
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 
@@ -24,80 +25,72 @@ import (
 	"github.com/external-secrets/external-secrets/pkg/provider/schema"
 	"github.com/external-secrets/external-secrets/pkg/provider/schema"
 )
 )
 
 
-var _ provider.Provider = &Client{}
+var (
+	errNotFound            = fmt.Errorf("secret value not found")
+	errMissingStore        = fmt.Errorf("missing store provider")
+	errMissingFakeProvider = fmt.Errorf("missing store provider fake")
+)
 
 
-// Client is a fake client for testing.
-type Client struct {
-	NewFn func(context.Context, esv1alpha1.GenericStore, client.Client,
-		string) (provider.SecretsClient, error)
-	GetSecretFn    func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error)
-	GetSecretMapFn func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error)
+type Provider struct {
+	config *esv1alpha1.FakeProvider
 }
 }
 
 
-// New returns a fake provider/client.
-func New() *Client {
-	v := &Client{
-		GetSecretFn: func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
-			return nil, nil
-		},
-		GetSecretMapFn: func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
-			return nil, nil
-		},
-	}
-
-	v.NewFn = func(context.Context, esv1alpha1.GenericStore, client.Client, string) (provider.SecretsClient, error) {
-		return v, nil
+func (p *Provider) NewClient(ctx context.Context, store esv1alpha1.GenericStore, kube client.Client, namespace string) (provider.SecretsClient, error) {
+	cfg, err := getProvider(store)
+	if err != nil {
+		return nil, err
 	}
 	}
-
-	return v
-}
-
-// RegisterAs registers the fake client in the schema.
-func (v *Client) RegisterAs(provider *esv1alpha1.SecretStoreProvider) {
-	schema.ForceRegister(v, provider)
+	return &Provider{
+		config: cfg,
+	}, nil
 }
 }
 
 
-// GetSecret implements the provider.Provider interface.
-func (v *Client) GetSecret(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
-	return v.GetSecretFn(ctx, ref)
+func getProvider(store esv1alpha1.GenericStore) (*esv1alpha1.FakeProvider, error) {
+	if store == nil {
+		return nil, errMissingStore
+	}
+	spc := store.GetSpec()
+	if spc == nil || spc.Provider == nil || spc.Provider.Fake == nil {
+		return nil, errMissingFakeProvider
+	}
+	return spc.Provider.Fake, nil
 }
 }
 
 
-// WithGetSecret wraps secret data returned by this provider.
-func (v *Client) WithGetSecret(secData []byte, err error) *Client {
-	v.GetSecretFn = func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
-		return secData, err
+// GetSecret returns a single secret from the provider.
+func (p *Provider) GetSecret(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
+	for _, data := range p.config.Data {
+		if data.Key == ref.Key && data.Version == ref.Version {
+			return []byte(data.Value), nil
+		}
 	}
 	}
-	return v
+	return nil, errNotFound
 }
 }
 
 
-// GetSecretMap imeplements the provider.Provider interface.
-func (v *Client) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
-	return v.GetSecretMapFn(ctx, ref)
-}
-func (v *Client) Close(ctx context.Context) error {
-	return nil
+// GetSecretMap returns multiple k/v pairs from the provider.
+func (p *Provider) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
+	for _, data := range p.config.Data {
+		if data.Key != ref.Key || data.Version != ref.Version || data.ValueMap == nil {
+			continue
+		}
+		return convertMap(data.ValueMap), nil
+	}
+	return nil, errNotFound
 }
 }
 
 
-// WithGetSecretMap wraps the secret data map returned by this fake provider.
-func (v *Client) WithGetSecretMap(secData map[string][]byte, err error) *Client {
-	v.GetSecretMapFn = func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
-		return secData, err
+func convertMap(in map[string]string) map[string][]byte {
+	m := make(map[string][]byte)
+	for k, v := range in {
+		m[k] = []byte(v)
 	}
 	}
-	return v
+	return m
 }
 }
 
 
-// WithNew wraps the fake provider factory function.
-func (v *Client) WithNew(f func(context.Context, esv1alpha1.GenericStore, client.Client,
-	string) (provider.SecretsClient, error)) *Client {
-	v.NewFn = f
-	return v
+func (p *Provider) Close(ctx context.Context) error {
+	return nil
 }
 }
 
 
-// NewClient returns a new fake provider.
-func (v *Client) NewClient(ctx context.Context, store esv1alpha1.GenericStore, kube client.Client, namespace string) (provider.SecretsClient, error) {
-	c, err := v.NewFn(ctx, store, kube, namespace)
-	if err != nil {
-		return nil, err
-	}
-	return c, nil
+func init() {
+	schema.Register(&Provider{}, &esv1alpha1.SecretStoreProvider{
+		Fake: &esv1alpha1.FakeProvider{},
+	})
 }
 }

+ 194 - 0
pkg/provider/fake/fake_test.go

@@ -0,0 +1,194 @@
+/*
+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
+
+    http://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 fake
+
+import (
+	"context"
+	"testing"
+
+	"github.com/onsi/gomega"
+
+	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
+)
+
+func TestNewClient(t *testing.T) {
+	p := &Provider{}
+	gomega.RegisterTestingT(t)
+
+	// nil store
+	_, err := p.NewClient(context.Background(), nil, nil, "")
+	gomega.Expect(err).To(gomega.HaveOccurred())
+
+	// missing provider
+	_, err = p.NewClient(context.Background(), &esv1alpha1.SecretStore{}, nil, "")
+	gomega.Expect(err).To(gomega.HaveOccurred())
+}
+
+func TestClose(t *testing.T) {
+	p := &Provider{}
+	gomega.RegisterTestingT(t)
+	err := p.Close(context.TODO())
+	gomega.Expect(err).ToNot(gomega.HaveOccurred())
+}
+
+type testCase struct {
+	name     string
+	input    []esv1alpha1.FakeProviderData
+	request  esv1alpha1.ExternalSecretDataRemoteRef
+	expValue string
+	expErr   string
+}
+
+func TestGetSecret(t *testing.T) {
+	gomega.RegisterTestingT(t)
+	p := &Provider{}
+	tbl := []testCase{
+		{
+			name:  "return err when not found",
+			input: []esv1alpha1.FakeProviderData{},
+			request: esv1alpha1.ExternalSecretDataRemoteRef{
+				Key:     "/foo",
+				Version: "v2",
+			},
+			expErr: "secret value not found",
+		},
+		{
+			name: "get correct value from multiple versions",
+			input: []esv1alpha1.FakeProviderData{
+				{
+					Key:     "/foo",
+					Value:   "bar2",
+					Version: "v2",
+				},
+				{
+					Key:   "junk",
+					Value: "xxxxx",
+				},
+				{
+					Key:     "/foo",
+					Value:   "bar1",
+					Version: "v1",
+				},
+			},
+			request: esv1alpha1.ExternalSecretDataRemoteRef{
+				Key:     "/foo",
+				Version: "v2",
+			},
+			expValue: "bar2",
+		},
+	}
+
+	for _, row := range tbl {
+		t.Run(row.name, func(t *testing.T) {
+			cl, err := p.NewClient(context.Background(), &esv1alpha1.SecretStore{
+				Spec: esv1alpha1.SecretStoreSpec{
+					Provider: &esv1alpha1.SecretStoreProvider{
+						Fake: &esv1alpha1.FakeProvider{
+							Data: row.input,
+						},
+					},
+				},
+			}, nil, "")
+			gomega.Expect(err).ToNot(gomega.HaveOccurred())
+			out, err := cl.GetSecret(context.Background(), row.request)
+			if row.expErr != "" {
+				gomega.Expect(err).To(gomega.MatchError(row.expErr))
+			} else {
+				gomega.Expect(err).ToNot(gomega.HaveOccurred())
+			}
+			gomega.Expect(string(out)).To(gomega.Equal(row.expValue))
+		})
+	}
+}
+
+type testMapCase struct {
+	name     string
+	input    []esv1alpha1.FakeProviderData
+	request  esv1alpha1.ExternalSecretDataRemoteRef
+	expValue map[string][]byte
+	expErr   string
+}
+
+func TestGetSecretMap(t *testing.T) {
+	gomega.RegisterTestingT(t)
+	p := &Provider{}
+	tbl := []testMapCase{
+		{
+			name:  "return err when not found",
+			input: []esv1alpha1.FakeProviderData{},
+			request: esv1alpha1.ExternalSecretDataRemoteRef{
+				Key:     "/foo",
+				Version: "v2",
+			},
+			expErr: "secret value not found",
+		},
+		{
+			name: "get correct value from multiple versions",
+			input: []esv1alpha1.FakeProviderData{
+				{
+					Key: "junk",
+					ValueMap: map[string]string{
+						"junk": "ok",
+					},
+				},
+				{
+					Key: "/foo",
+					ValueMap: map[string]string{
+						"foo": "bar",
+						"baz": "bang",
+					},
+					Version: "v1",
+				},
+				{
+					Key: "/foo",
+					ValueMap: map[string]string{
+						"foo": "bar",
+						"baz": "bang",
+					},
+					Version: "v2",
+				},
+			},
+			request: esv1alpha1.ExternalSecretDataRemoteRef{
+				Key:     "/foo",
+				Version: "v2",
+			},
+			expValue: map[string][]byte{
+				"foo": []byte("bar"),
+				"baz": []byte("bang"),
+			},
+		},
+	}
+
+	for _, row := range tbl {
+		t.Run(row.name, func(t *testing.T) {
+			cl, err := p.NewClient(context.Background(), &esv1alpha1.SecretStore{
+				Spec: esv1alpha1.SecretStoreSpec{
+					Provider: &esv1alpha1.SecretStoreProvider{
+						Fake: &esv1alpha1.FakeProvider{
+							Data: row.input,
+						},
+					},
+				},
+			}, nil, "")
+			gomega.Expect(err).ToNot(gomega.HaveOccurred())
+			out, err := cl.GetSecretMap(context.Background(), row.request)
+			if row.expErr != "" {
+				gomega.Expect(err).To(gomega.MatchError(row.expErr))
+			} else {
+				gomega.Expect(err).ToNot(gomega.HaveOccurred())
+			}
+			gomega.Expect(out).To(gomega.Equal(row.expValue))
+		})
+	}
+}

+ 1 - 1
pkg/provider/gcp/secretmanager/fake/fake.go

@@ -19,7 +19,7 @@ import (
 
 
 	"github.com/google/go-cmp/cmp"
 	"github.com/google/go-cmp/cmp"
 	"github.com/google/go-cmp/cmp/cmpopts"
 	"github.com/google/go-cmp/cmp/cmpopts"
-	grpc "github.com/googleapis/gax-go"
+	grpc "github.com/googleapis/gax-go/v2"
 	secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1"
 	secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1"
 )
 )
 
 

+ 1 - 1
pkg/provider/gcp/secretmanager/secretsmanager.go

@@ -19,7 +19,7 @@ import (
 	"fmt"
 	"fmt"
 
 
 	secretmanager "cloud.google.com/go/secretmanager/apiv1"
 	secretmanager "cloud.google.com/go/secretmanager/apiv1"
-	"github.com/googleapis/gax-go"
+	"github.com/googleapis/gax-go/v2"
 	"github.com/tidwall/gjson"
 	"github.com/tidwall/gjson"
 	"golang.org/x/oauth2"
 	"golang.org/x/oauth2"
 	"golang.org/x/oauth2/google"
 	"golang.org/x/oauth2/google"

+ 1 - 1
pkg/provider/gcp/secretmanager/secretsmanager_workload_identity.go

@@ -24,7 +24,7 @@ import (
 
 
 	iam "cloud.google.com/go/iam/credentials/apiv1"
 	iam "cloud.google.com/go/iam/credentials/apiv1"
 	secretmanager "cloud.google.com/go/secretmanager/apiv1"
 	secretmanager "cloud.google.com/go/secretmanager/apiv1"
-	"github.com/googleapis/gax-go"
+	"github.com/googleapis/gax-go/v2"
 	"golang.org/x/oauth2"
 	"golang.org/x/oauth2"
 	"google.golang.org/api/option"
 	"google.golang.org/api/option"
 	credentialspb "google.golang.org/genproto/googleapis/iam/credentials/v1"
 	credentialspb "google.golang.org/genproto/googleapis/iam/credentials/v1"

+ 1 - 1
pkg/provider/gcp/secretmanager/secretsmanager_workload_identity_test.go

@@ -21,7 +21,7 @@ import (
 	"net/http/httptest"
 	"net/http/httptest"
 	"testing"
 	"testing"
 
 
-	"github.com/googleapis/gax-go"
+	"github.com/googleapis/gax-go/v2"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/assert"
 	"golang.org/x/oauth2"
 	"golang.org/x/oauth2"
 	credentialspb "google.golang.org/genproto/googleapis/iam/credentials/v1"
 	credentialspb "google.golang.org/genproto/googleapis/iam/credentials/v1"

+ 1 - 0
pkg/provider/register/register.go

@@ -21,6 +21,7 @@ import (
 	_ "github.com/external-secrets/external-secrets/pkg/provider/alibaba"
 	_ "github.com/external-secrets/external-secrets/pkg/provider/alibaba"
 	_ "github.com/external-secrets/external-secrets/pkg/provider/aws"
 	_ "github.com/external-secrets/external-secrets/pkg/provider/aws"
 	_ "github.com/external-secrets/external-secrets/pkg/provider/azure/keyvault"
 	_ "github.com/external-secrets/external-secrets/pkg/provider/azure/keyvault"
+	_ "github.com/external-secrets/external-secrets/pkg/provider/fake"
 	_ "github.com/external-secrets/external-secrets/pkg/provider/gcp/secretmanager"
 	_ "github.com/external-secrets/external-secrets/pkg/provider/gcp/secretmanager"
 	_ "github.com/external-secrets/external-secrets/pkg/provider/gitlab"
 	_ "github.com/external-secrets/external-secrets/pkg/provider/gitlab"
 	_ "github.com/external-secrets/external-secrets/pkg/provider/ibm"
 	_ "github.com/external-secrets/external-secrets/pkg/provider/ibm"

+ 103 - 0
pkg/provider/testing/fake/fake.go

@@ -0,0 +1,103 @@
+/*
+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
+
+    http://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 fake
+
+import (
+	"context"
+
+	"sigs.k8s.io/controller-runtime/pkg/client"
+
+	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
+	"github.com/external-secrets/external-secrets/pkg/provider"
+	"github.com/external-secrets/external-secrets/pkg/provider/schema"
+)
+
+var _ provider.Provider = &Client{}
+
+// Client is a fake client for testing.
+type Client struct {
+	NewFn func(context.Context, esv1alpha1.GenericStore, client.Client,
+		string) (provider.SecretsClient, error)
+	GetSecretFn    func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error)
+	GetSecretMapFn func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error)
+}
+
+// New returns a fake provider/client.
+func New() *Client {
+	v := &Client{
+		GetSecretFn: func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
+			return nil, nil
+		},
+		GetSecretMapFn: func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
+			return nil, nil
+		},
+	}
+
+	v.NewFn = func(context.Context, esv1alpha1.GenericStore, client.Client, string) (provider.SecretsClient, error) {
+		return v, nil
+	}
+
+	return v
+}
+
+// RegisterAs registers the fake client in the schema.
+func (v *Client) RegisterAs(provider *esv1alpha1.SecretStoreProvider) {
+	schema.ForceRegister(v, provider)
+}
+
+// GetSecret implements the provider.Provider interface.
+func (v *Client) GetSecret(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
+	return v.GetSecretFn(ctx, ref)
+}
+
+// WithGetSecret wraps secret data returned by this provider.
+func (v *Client) WithGetSecret(secData []byte, err error) *Client {
+	v.GetSecretFn = func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
+		return secData, err
+	}
+	return v
+}
+
+// GetSecretMap imeplements the provider.Provider interface.
+func (v *Client) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
+	return v.GetSecretMapFn(ctx, ref)
+}
+func (v *Client) Close(ctx context.Context) error {
+	return nil
+}
+
+// WithGetSecretMap wraps the secret data map returned by this fake provider.
+func (v *Client) WithGetSecretMap(secData map[string][]byte, err error) *Client {
+	v.GetSecretMapFn = func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
+		return secData, err
+	}
+	return v
+}
+
+// WithNew wraps the fake provider factory function.
+func (v *Client) WithNew(f func(context.Context, esv1alpha1.GenericStore, client.Client,
+	string) (provider.SecretsClient, error)) *Client {
+	v.NewFn = f
+	return v
+}
+
+// NewClient returns a new fake provider.
+func (v *Client) NewClient(ctx context.Context, store esv1alpha1.GenericStore, kube client.Client, namespace string) (provider.SecretsClient, error) {
+	c, err := v.NewFn(ctx, store, kube, namespace)
+	if err != nil {
+		return nil, err
+	}
+	return c, nil
+}

+ 3 - 1
pkg/provider/webhook/webhook_test.go

@@ -298,7 +298,9 @@ func testGetSecret(tc testCase, t *testing.T, client provider.SecretsClient) {
 		Key:     tc.Args.Key,
 		Key:     tc.Args.Key,
 		Version: tc.Args.Version,
 		Version: tc.Args.Version,
 	}
 	}
-	secret, err := client.GetSecret(context.Background(), testRef)
+	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
+	defer cancel()
+	secret, err := client.GetSecret(ctx, testRef)
 	errStr := ""
 	errStr := ""
 	if err != nil {
 	if err != nil {
 		errStr = err.Error()
 		errStr = err.Error()

+ 19 - 0
terraform/aws/modules/cluster/irsa.tf

@@ -37,6 +37,25 @@ resource "aws_iam_role" "eso-e2e-irsa" {
     "arn:aws:iam::aws:policy/SecretsManagerReadWrite"
     "arn:aws:iam::aws:policy/SecretsManagerReadWrite"
   ]
   ]
 
 
+  inline_policy {
+    name = "aws_ssm_parameterstore"
+
+    policy = jsonencode({
+      Version = "2012-10-17"
+      Statement = [
+        {
+          Action = [
+            "ssm:GetParameter",
+            "ssm:PutParameter",
+          ]
+          Effect   = "Allow"
+          Resource = "*"
+        },
+      ]
+    })
+  }
+
+
 }
 }
 
 
 resource "null_resource" "apply_sa" {
 resource "null_resource" "apply_sa" {