Jelajahi Sumber

Merge pull request #618 from external-secrets/feature/aws-e2e-managed

feat(e2e): implement aws tests, enhance gcp tests
paul-the-alien[bot] 4 tahun lalu
induk
melakukan
0b9c142a22
61 mengubah file dengan 1330 tambahan dan 731 penghapusan
  1. 78 34
      .github/workflows/e2e-managed.yml
  2. 4 4
      .github/workflows/e2e.yml
  3. 1 0
      .github/workflows/ok-to-test-managed.yml
  4. 17 21
      Makefile
  5. 1 1
      e2e/Dockerfile
  6. 14 32
      e2e/Makefile
  7. 3 12
      e2e/e2e_test.go
  8. 6 9
      e2e/entrypoint.sh
  9. 1 1
      e2e/framework/addon/addon.go
  10. 1 1
      e2e/framework/addon/chart.go
  11. 64 57
      e2e/framework/addon/eso.go
  12. 0 44
      e2e/framework/addon/localstack.go
  13. 1 1
      e2e/framework/addon/vault.go
  14. 1 1
      e2e/framework/eso.go
  15. 7 10
      e2e/framework/framework.go
  16. 2 4
      e2e/framework/log/log.go
  17. 13 9
      e2e/framework/util/util.go
  18. 0 12
      e2e/k8s/eso.scoped.values.yaml
  19. 0 11
      e2e/k8s/eso.values.yaml
  20. 12 8
      e2e/run.sh
  21. 4 8
      e2e/suite/akeyless/akeyless.go
  22. 8 1
      e2e/suite/akeyless/provider.go
  23. 4 12
      e2e/suite/alibaba/alibaba.go
  24. 9 1
      e2e/suite/alibaba/provider.go
  25. 150 33
      e2e/suite/aws/provider.go
  26. 4 91
      e2e/suite/aws/secretsmanager.go
  27. 102 0
      e2e/suite/aws/secretsmanager_managed.go
  28. 3 14
      e2e/suite/azure/azure.go
  29. 21 5
      e2e/suite/azure/provider.go
  30. 55 63
      e2e/suite/gcp/gcp.go
  31. 111 0
      e2e/suite/gcp/gcp_managed.go
  32. 107 101
      e2e/suite/gcp/provider.go
  33. 0 86
      e2e/suite/gcpmanaged/gcpmanaged.go
  34. 5 13
      e2e/suite/gitlab/gitlab.go
  35. 8 1
      e2e/suite/gitlab/provider.go
  36. 0 1
      e2e/suite/import.go
  37. 4 10
      e2e/suite/oracle/oracle.go
  38. 11 1
      e2e/suite/oracle/provider.go
  39. 1 1
      e2e/suite/vault/provider.go
  40. 4 6
      e2e/suite/vault/vault.go
  41. 2 3
      go.mod
  42. 4 0
      go.sum
  43. 1 1
      main.go
  44. 1 2
      pkg/controllers/externalsecret/externalsecret_controller_test.go
  45. 2 2
      pkg/controllers/externalsecret/suite_test.go
  46. 2 2
      pkg/controllers/secretstore/suite_test.go
  47. 8 0
      terraform/aws/main.tf
  48. 60 0
      terraform/aws/modules/cluster/auth.tf
  49. 57 0
      terraform/aws/modules/cluster/irsa.tf
  50. 127 0
      terraform/aws/modules/cluster/main.tf
  51. 135 0
      terraform/aws/modules/cluster/outputs.tf
  52. 10 0
      terraform/aws/modules/cluster/provider.tf
  53. 16 0
      terraform/aws/modules/cluster/variables.tf
  54. 11 0
      terraform/aws/outputs.tf
  55. 11 0
      terraform/aws/provider.tf
  56. 19 0
      terraform/aws/variables.tf
  57. 20 0
      terraform/gcp/eso_gcp_modules/gke/main.tf
  58. 2 0
      terraform/gcp/eso_gcp_modules/network/main.tf
  59. 3 0
      terraform/gcp/eso_gcp_modules/network/variable.tf
  60. 1 0
      terraform/gcp/main.tf
  61. 1 1
      tools.go

+ 78 - 34
.github/workflows/e2e-managed.yml

@@ -24,24 +24,62 @@ env:
   GCP_KSA_NAME: ${{ secrets.GCP_KSA_NAME}} # Kubernetes Service Account
   GCP_KSA_NAME: ${{ secrets.GCP_KSA_NAME}} # Kubernetes Service Account
   TF_VAR_GCP_GSA_NAME: ${{ secrets.GCP_GSA_NAME}} # Goolge Service Account for tf
   TF_VAR_GCP_GSA_NAME: ${{ secrets.GCP_GSA_NAME}} # Goolge Service Account for tf
   TF_VAR_GCP_KSA_NAME: ${{ secrets.GCP_KSA_NAME}} # Kubernetes Service Account for tf
   TF_VAR_GCP_KSA_NAME: ${{ secrets.GCP_KSA_NAME}} # Kubernetes Service Account for tf
+  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
+  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+  AWS_SA_NAME: ${{ secrets.AWS_SA_NAME }}
+  AWS_SA_NAMESPACE: ${{ secrets.AWS_SA_NAMESPACE }}
+  AWS_REGION: "eu-west-1"
+  AWS_CLUSTER_NAME: "eso-e2e-managed"
+  TF_VAR_AWS_SA_NAME: ${{ secrets.AWS_SA_NAME }}
+  TF_VAR_AWS_SA_NAMESPACE: ${{ secrets.AWS_SA_NAMESPACE }}
+  TF_VAR_AWS_REGION: "eu-west-1"
+  TF_VAR_AWS_CLUSTER_NAME: "eso-e2e-managed"
+
   AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID}}
   AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID}}
   AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET}}
   AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET}}
   TENANT_ID: ${{ secrets.TENANT_ID}}
   TENANT_ID: ${{ secrets.TENANT_ID}}
   VAULT_URL: ${{ secrets.VAULT_URL}}
   VAULT_URL: ${{ secrets.VAULT_URL}}
-  IMAGE_REGISTRY: ghcr.io/external-secrets/external-secrets
-  E2E_IMAGE_REGISTRY: ghcr.io/external-secrets/external-secrets-e2e
-  E2E_VERSION: test
 
 
 name: e2e tests
 name: e2e tests
 
 
 jobs:
 jobs:
-  # Repo owner has commented /ok-to-test-managed on a (fork-based) pull request
-  integration-fork-managed:
+  integration-managed:
     runs-on: ubuntu-latest
     runs-on: ubuntu-latest
-    if:
-      github.event_name == 'repository_dispatch'
+    if: github.event_name == 'repository_dispatch'
+
     steps:
     steps:
 
 
+    # set status=in_progress
+    - uses: actions/github-script@v1
+      id: update-check-run
+      env:
+        number: ${{ github.event.client_payload.slash_command.args.named.pull }}
+        job: ${{ github.job }}
+        conclusion: ${{ job.status }}
+      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
+          });
+          console.log("\n\nPR CHECKS: " + checks)
+          const check = checks.check_runs.filter(c => c.name === process.env.job);
+          console.log("\n\nPR Filtered CHECK: " + check)
+          console.log(check)
+          const { data: result } = await github.checks.update({
+            ...context.repo,
+            check_run_id: check[0].id,
+            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
@@ -75,13 +113,7 @@ jobs:
         path: ${{ steps.go.outputs.mod-cache }}
         path: ${{ steps.go.outputs.mod-cache }}
         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: Setup gcloud CLI
-      uses: google-github-actions/setup-gcloud@master
-      with:
-        service_account_key: ${{ env.GCP_SM_SA_GKE_JSON }}
-        project_id: ${{ env.GCP_PROJECT_ID }}
-    
+
     - name: Setup TFLint
     - name: Setup TFLint
       uses: terraform-linters/setup-tflint@v1
       uses: terraform-linters/setup-tflint@v1
       with:
       with:
@@ -91,40 +123,52 @@ jobs:
       run: find ${{ github.workspace }} | grep tf$ | xargs -n1 dirname | xargs -IXXX -n1 /bin/sh -c 'set -o errexit; cd XXX; pwd; tflint --loglevel=info .; cd - >/dev/null'
       run: find ${{ github.workspace }} | grep tf$ | xargs -n1 dirname | xargs -IXXX -n1 /bin/sh -c 'set -o errexit; cd XXX; pwd; tflint --loglevel=info .; cd - >/dev/null'
 
 
     - name: Setup TF Gcloud Provider
     - name: Setup TF Gcloud Provider
+      if: github.event.client_payload.slash_command.args.named.provider == 'gcp'
       run: |-
       run: |-
         mkdir -p terraform/gcp/secrets
         mkdir -p terraform/gcp/secrets
         echo ${GCP_SM_SA_GKE_JSON} > terraform/gcp/secrets/gcloud-service-account-key.json
         echo ${GCP_SM_SA_GKE_JSON} > terraform/gcp/secrets/gcloud-service-account-key.json
 
 
-    - name: Show TF GKE
+    - name: Show TF
       run: |-
       run: |-
-        make tf.show.gcp
+        PROVIDER=${{github.event.client_payload.slash_command.args.named.provider}}
+        make tf.show.${PROVIDER}
 
 
     - name: Setup Infracost
     - name: Setup Infracost
       uses: infracost/actions/setup@v1
       uses: infracost/actions/setup@v1
       with:
       with:
         api-key: ${{ secrets.INFRACOST_API_KEY }}
         api-key: ${{ secrets.INFRACOST_API_KEY }}
 
 
-    - name: Generate Infracost JSON for GKE
-      run: infracost breakdown --path terraform/gcp/plan.json --format json --out-file /tmp/infracost.json
+    - name: Generate Infracost JSON for provider
+      run: infracost breakdown --path terraform/${{github.event.client_payload.slash_command.args.named.provider}}/plan.json --format json --out-file /tmp/infracost.json
 
 
     - name: Post Infracost comment
     - name: Post Infracost comment
       uses: infracost/actions/comment@v1
       uses: infracost/actions/comment@v1
       with:
       with:
         path: /tmp/infracost.json
         path: /tmp/infracost.json
-        # Choose the commenting behavior, 'update' is a good default:
-        behavior: update # Create a single comment and update it. The "quietest" option.                 
-        # behavior: delete-and-new # Delete previous comments and create a new one.
-        # behavior: hide-and-new # Minimize previous comments and create a new one.
-        # behavior: new # Create a new cost estimate comment on every push.
+        behavior: update
 
 
-    - name: Apply TF GKE
+    - name: Apply TF
       run: |-
       run: |-
-        make tf.apply.gcp
+        PROVIDER=${{github.event.client_payload.slash_command.args.named.provider}}
+        make tf.apply.${PROVIDER}
+
+    - name: Setup gcloud CLI
+      if: github.event.client_payload.slash_command.args.named.provider == 'gcp'
+      uses: google-github-actions/setup-gcloud@master
+      with:
+        service_account_key: ${{ env.GCP_SM_SA_GKE_JSON }}
+        project_id: ${{ env.GCP_PROJECT_ID }}
 
 
     - name: Get the GKE credentials
     - name: Get the GKE credentials
+      if: github.event.client_payload.slash_command.args.named.provider == 'gke'
       run: |-
       run: |-
         gcloud container clusters get-credentials "$GCP_GKE_CLUSTER" --zone "$GCP_GKE_ZONE" --project "$GCP_PROJECT_ID"
         gcloud container clusters get-credentials "$GCP_GKE_CLUSTER" --zone "$GCP_GKE_ZONE" --project "$GCP_PROJECT_ID"
 
 
+    - name: Get the AWS credentials
+      if: github.event.client_payload.slash_command.args.named.provider == 'aws'
+      run: |-
+        aws --region $AWS_REGION eks update-kubeconfig --name $AWS_CLUSTER_NAME
+
     - name: Login to Docker
     - name: Login to Docker
       uses: docker/login-action@v1
       uses: docker/login-action@v1
       if: env.GHCR_USERNAME != ''
       if: env.GHCR_USERNAME != ''
@@ -133,25 +177,25 @@ jobs:
         username: ${{ secrets.GHCR_USERNAME }}
         username: ${{ secrets.GHCR_USERNAME }}
         password: ${{ secrets.GHCR_TOKEN }}
         password: ${{ secrets.GHCR_TOKEN }}
 
 
-    - name: Run e2e Tests for GCP
+    - name: Run managed e2e Tests
       run: |
       run: |
-        export E2E_VERSION=$GITHUB_SHA
-        export PR_IMG_TAG=$GITHUB_SHA
         export PATH=$PATH:$(go env GOPATH)/bin
         export PATH=$PATH:$(go env GOPATH)/bin
-        go get github.com/onsi/ginkgo/ginkgo
-        make test.e2e.managed FOCUS="gcpmanaged"
+        PROVIDER=${{github.event.client_payload.slash_command.args.named.provider}}
+        go get github.com/onsi/ginkgo/v2/ginkgo
+        make test.e2e.managed GINKGO_LABELS="${PROVIDER}"
 
 
-    - name: Destroy TF GKE
+    - name: Destroy TF
       if: always()
       if: always()
       run: |-
       run: |-
-        make tf.destroy.gcp
+        PROVIDER=${{github.event.client_payload.slash_command.args.named.provider}}
+        make tf.destroy.${PROVIDER}
 
 
-    # Update check run called "integration-fork"
+    # set status=completed
     - uses: actions/github-script@v1
     - uses: actions/github-script@v1
       id: update-check-run
       id: update-check-run
       if: ${{ always() }}
       if: ${{ always() }}
       env:
       env:
-        number: ${{ github.event.client_payload.pull_request.number }}
+        number: ${{ github.event.client_payload.slash_command.args.named.pull }}
         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 }}

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

@@ -19,12 +19,12 @@ env:
   GCP_GSA_NAME: ${{ secrets.GCP_GSA_NAME}} # Goolge Service Account
   GCP_GSA_NAME: ${{ secrets.GCP_GSA_NAME}} # Goolge Service Account
   GCP_KSA_NAME: ${{ secrets.GCP_KSA_NAME}} # Kubernetes Service Account
   GCP_KSA_NAME: ${{ secrets.GCP_KSA_NAME}} # Kubernetes Service Account
   GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID}}
   GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID}}
+  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
+  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
   AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID}}
   AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID}}
   AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET}}
   AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET}}
   TENANT_ID: ${{ secrets.TENANT_ID}}
   TENANT_ID: ${{ secrets.TENANT_ID}}
   VAULT_URL: ${{ secrets.VAULT_URL}}
   VAULT_URL: ${{ secrets.VAULT_URL}}
-  E2E_IMAGE_REGISTRY: local/external-secrets-e2e
-  E2E_VERSION: test
 
 
 name: e2e tests
 name: e2e tests
 
 
@@ -87,7 +87,7 @@ jobs:
         BUILD_ARGS: "--load"
         BUILD_ARGS: "--load"
       run: |
       run: |
         export PATH=$PATH:$(go env GOPATH)/bin
         export PATH=$PATH:$(go env GOPATH)/bin
-        go get github.com/onsi/ginkgo/ginkgo
+        go get github.com/onsi/ginkgo/v2/ginkgo
         make test.e2e
         make test.e2e
 
 
   # Repo owner has commented /ok-to-test on a (fork-based) pull request
   # Repo owner has commented /ok-to-test on a (fork-based) pull request
@@ -150,7 +150,7 @@ jobs:
         BUILD_ARGS: "--load"
         BUILD_ARGS: "--load"
       run: |
       run: |
         export PATH=$PATH:$(go env GOPATH)/bin
         export PATH=$PATH:$(go env GOPATH)/bin
-        go get github.com/onsi/ginkgo/ginkgo
+        go get github.com/onsi/ginkgo/v2/ginkgo
         make test.e2e
         make test.e2e
 
 
     # Update check run called "integration-fork"
     # Update check run called "integration-fork"

+ 1 - 0
.github/workflows/ok-to-test-managed.yml

@@ -30,6 +30,7 @@ jobs:
         token: ${{ env.TOKEN }} # GitHub App installation access token
         token: ${{ env.TOKEN }} # GitHub App installation access token
         # token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} # PAT or OAuth token will also work
         # token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} # PAT or OAuth token will also work
         reaction-token: ${{ secrets.GITHUB_TOKEN }}
         reaction-token: ${{ secrets.GITHUB_TOKEN }}
+        static-args: pull=${{ github.event.client_payload.pull_request.number }}
         issue-type: pull-request
         issue-type: pull-request
         commands: ok-to-test-managed
         commands: ok-to-test-managed
         permission: maintain
         permission: maintain

+ 17 - 21
Makefile

@@ -14,9 +14,7 @@ BUILD_ARGS ?=
 all: $(addprefix build-,$(ARCH))
 all: $(addprefix build-,$(ARCH))
 
 
 # Image registry for build/push image targets
 # Image registry for build/push image targets
-IMAGE_REGISTRY ?= ghcr.io/external-secrets/external-secrets
-
-PR_IMG_TAG ?=
+export IMAGE_REGISTRY ?= ghcr.io/external-secrets/external-secrets
 
 
 CRD_DIR     ?= deploy/crds
 CRD_DIR     ?= deploy/crds
 
 
@@ -35,10 +33,10 @@ endif
 # check if there are any existing `git tag` values
 # check if there are any existing `git tag` values
 ifeq ($(shell git tag),)
 ifeq ($(shell git tag),)
 # no tags found - default to initial tag `v0.0.0`
 # no tags found - default to initial tag `v0.0.0`
-VERSION := $(shell echo "v0.0.0-$$(git rev-list HEAD --count)-g$$(git describe --dirty --always)" | sed 's/-/./2' | sed 's/-/./2')
+export VERSION := $(shell echo "v0.0.0-$$(git rev-list HEAD --count)-g$$(git describe --dirty --always)" | sed 's/-/./2' | sed 's/-/./2')
 else
 else
 # use tags
 # use tags
-VERSION := $(shell git describe --dirty --always --tags --exclude 'helm*' | sed 's/-/./2' | sed 's/-/./2')
+export VERSION := $(shell git describe --dirty --always --tags --exclude 'helm*' | sed 's/-/./2' | sed 's/-/./2')
 endif
 endif
 
 
 # ====================================================================================
 # ====================================================================================
@@ -87,13 +85,13 @@ test: generate ## Run tests
 test.e2e: generate ## Run e2e tests
 test.e2e: generate ## Run e2e tests
 	@$(INFO) go test e2e-tests
 	@$(INFO) go test e2e-tests
 	$(MAKE) -C ./e2e test
 	$(MAKE) -C ./e2e test
-	@$(OK) go test unit-tests
+	@$(OK) go test e2e-tests
 
 
 .PHONY: test.e2e.managed
 .PHONY: test.e2e.managed
-test.e2e.managed: generate ## Run e2e tests
-	@$(INFO) go test e2e-tests
+test.e2e.managed: generate ## Run e2e tests managed
+	@$(INFO) go test e2e-tests-managed
 	$(MAKE) -C ./e2e test.managed
 	$(MAKE) -C ./e2e test.managed
-	@$(OK) go test unit-tests
+	@$(OK) go test e2e-tests-managed
 
 
 .PHONY: build
 .PHONY: build
 build: $(addprefix build-,$(ARCH)) ## Build binary
 build: $(addprefix build-,$(ARCH)) ## Build binary
@@ -211,7 +209,7 @@ docker.push: ## Push the docker image to the registry
 	@docker push $(IMAGE_REGISTRY):$(VERSION)
 	@docker push $(IMAGE_REGISTRY):$(VERSION)
 	@$(OK) docker push
 	@$(OK) docker push
 
 
-# RELEASE_TAG is tag to promote. Default is promooting to main branch, but can be overriden
+# RELEASE_TAG is tag to promote. Default is promoting to main branch, but can be overriden
 # to promote a tag to a specific version.
 # to promote a tag to a specific version.
 RELEASE_TAG ?= main
 RELEASE_TAG ?= main
 SOURCE_TAG ?= $(VERSION)
 SOURCE_TAG ?= $(VERSION)
@@ -230,29 +228,27 @@ docker.promote: ## Promote the docker image to the registry
 # ====================================================================================
 # ====================================================================================
 # Terraform
 # Terraform
 
 
-tf.plan.gcp: ## Runs terrform plan for gcp provider bringing GKE up
-	@cd $(TF_DIR)/gcp; \
+tf.plan.%: ## Runs terrform plan for a provider
+	@cd $(TF_DIR)/$*; \
 	terraform init; \
 	terraform init; \
-	terraform plan -auto-approve
+	terraform plan
 
 
-tf.apply.gcp: ## Runs terrform apply for gcp provider bringing GKE up
-	@cd $(TF_DIR)/gcp; \
+tf.apply.%: ## Runs terrform apply for a provider
+	@cd $(TF_DIR)/$*; \
 	terraform init; \
 	terraform init; \
 	terraform apply -auto-approve
 	terraform apply -auto-approve
 
 
-tf.destroy.gcp: ## Runs terrform destroy for gcp provider bringing GKE down
-	@cd $(TF_DIR)/gcp; \
+tf.destroy.%: ## Runs terrform destroy for a provider
+	@cd $(TF_DIR)/$*; \
 	terraform init; \
 	terraform init; \
 	terraform destroy -auto-approve
 	terraform destroy -auto-approve
 
 
-tf.show.gcp: ## Runs terrform show for gcp and outputs to a file
-	@cd $(TF_DIR)/gcp; \
+tf.show.%: ## Runs terrform show for a provider and outputs to a file
+	@cd $(TF_DIR)/$*; \
 	terraform init; \
 	terraform init; \
 	terraform plan -out tfplan.binary; \
 	terraform plan -out tfplan.binary; \
 	terraform show -json tfplan.binary > plan.json
 	terraform show -json tfplan.binary > plan.json
 
 
-
-
 # ====================================================================================
 # ====================================================================================
 # Help
 # Help
 
 

+ 1 - 1
e2e/Dockerfile

@@ -4,7 +4,7 @@ FROM golang:$GO_VERSION-buster as builder
 ENV KUBECTL_VERSION="v1.21.2"
 ENV KUBECTL_VERSION="v1.21.2"
 ENV HELM_VERSION="v3.7.1"
 ENV HELM_VERSION="v3.7.1"
 
 
-RUN go get -u github.com/onsi/ginkgo/ginkgo
+RUN go get -u github.com/onsi/ginkgo/v2/ginkgo
 RUN wget -q https://storage.googleapis.com/kubernetes-release/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl -O /usr/local/bin/kubectl && \
 RUN wget -q https://storage.googleapis.com/kubernetes-release/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl -O /usr/local/bin/kubectl && \
     chmod +x /usr/local/bin/kubectl && \
     chmod +x /usr/local/bin/kubectl && \
     wget -q https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz -O - | tar -xzO linux-amd64/helm > /usr/local/bin/helm && \
     wget -q https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz -O - | tar -xzO linux-amd64/helm > /usr/local/bin/helm && \

+ 14 - 32
e2e/Makefile

@@ -2,15 +2,11 @@ MAKEFLAGS   += --warn-undefined-variables
 SHELL       := /bin/bash
 SHELL       := /bin/bash
 .SHELLFLAGS := -euo pipefail -c
 .SHELLFLAGS := -euo pipefail -c
 
 
-IMG_TAG     = test
-IMG         = local/external-secrets-e2e:$(IMG_TAG)
-KIND_IMG    = "kindest/node:v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6"
-BUILD_ARGS  ?=
-IMAGE_REGISTRY ?=
-export FOCUS := $(FOCUS)
+KIND_IMG       = "kindest/node:v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6"
+BUILD_ARGS     ?=
 
 
-export E2E_IMAGE_REGISTRY ?=
-export E2E_VERSION ?=
+export E2E_IMAGE_REGISTRY ?= ghcr.io/external-secrets/external-secrets-e2e
+export GINKGO_LABELS ?= !managed
 
 
 start-kind: ## Start kind cluster
 start-kind: ## Start kind cluster
 	kind create cluster \
 	kind create cluster \
@@ -21,49 +17,35 @@ start-kind: ## Start kind cluster
 
 
 test: e2e-image ## Run e2e tests against current kube context
 test: e2e-image ## Run e2e tests against current kube context
 	$(MAKE) -C ../ docker.build \
 	$(MAKE) -C ../ docker.build \
-		IMAGE_REGISTRY=local/external-secrets \
-		VERSION=$(IMG_TAG) \
+		IMAGE_REGISTRY=$(IMAGE_REGISTRY) \
+		VERSION=$(VERSION) \
 		ARCH=amd64 \
 		ARCH=amd64 \
 		BUILD_ARGS="${BUILD_ARGS} --build-arg TARGETARCH=amd64 --build-arg TARGETOS=linux"
 		BUILD_ARGS="${BUILD_ARGS} --build-arg TARGETARCH=amd64 --build-arg TARGETOS=linux"
-	kind load docker-image --name="external-secrets" local/external-secrets:$(IMG_TAG)
-	kind load docker-image --name="external-secrets" $(IMG)
+	kind load docker-image --name="external-secrets" $(IMAGE_REGISTRY):$(VERSION)
+	kind load docker-image --name="external-secrets" $(E2E_IMAGE_REGISTRY):$(VERSION)
 	./run.sh
 	./run.sh
 
 
-test.managed: e2e-remote-values e2e-image.managed  ## Run e2e tests against current kube context
+test.managed: e2e-image ## Run e2e tests against current kube context
 	$(MAKE) -C ../ docker.build \
 	$(MAKE) -C ../ docker.build \
-		VERSION=$(PR_IMG_TAG) \
+		VERSION=$(VERSION) \
 		ARCH=amd64 \
 		ARCH=amd64 \
 		BUILD_ARGS="${BUILD_ARGS} --build-arg TARGETARCH=amd64 --build-arg TARGETOS=linux"
 		BUILD_ARGS="${BUILD_ARGS} --build-arg TARGETARCH=amd64 --build-arg TARGETOS=linux"
 	$(MAKE) -C ../ docker.push \
 	$(MAKE) -C ../ docker.push \
-		VERSION=$(PR_IMG_TAG)
+		VERSION=$(VERSION)
 	$(MAKE) -C ../ docker.push \
 	$(MAKE) -C ../ docker.push \
 		IMAGE_REGISTRY=$(E2E_IMAGE_REGISTRY) \
 		IMAGE_REGISTRY=$(E2E_IMAGE_REGISTRY) \
-		VERSION=$(E2E_VERSION)
+		VERSION=$(VERSION)
 	./run.sh
 	./run.sh
 
 
-e2e-remote-values:
-	sed -i "s|repository: [^ ]*|repository: $(IMAGE_REGISTRY)|g" k8s/eso.values.yaml
-	sed -i "s|tag: [^ ]*|tag: $(PR_IMG_TAG)|g" k8s/eso.values.yaml
-	sed -i "s|repository: [^ ]*|repository: $(IMAGE_REGISTRY)|g" k8s/eso.scoped.values.yaml
-	sed -i "s|tag: [^ ]*|tag: $(PR_IMG_TAG)|g" k8s/eso.scoped.values.yaml
-
-
 e2e-bin:
 e2e-bin:
-	CGO_ENABLED=0 go run github.com/onsi/ginkgo/ginkgo build .
+	CGO_ENABLED=0 go run github.com/onsi/ginkgo/v2/ginkgo build .
 
 
 e2e-image: e2e-bin
 e2e-image: e2e-bin
 	-rm -rf ./k8s/deploy
 	-rm -rf ./k8s/deploy
 	mkdir -p k8s
 	mkdir -p k8s
 	$(MAKE) -C ../ helm.generate
 	$(MAKE) -C ../ helm.generate
 	cp -r ../deploy ./k8s
 	cp -r ../deploy ./k8s
-	docker build $(BUILD_ARGS) -t $(IMG) .
-
-e2e-image.managed: e2e-bin
-	-rm -rf ./k8s/deploy
-	mkdir -p k8s
-	$(MAKE) -C ../ helm.generate
-	cp -r ../deploy ./k8s
-	docker build $(BUILD_ARGS) -t ghcr.io/external-secrets/external-secrets-e2e:$(E2E_VERSION) .
+	docker build $(BUILD_ARGS) -t $(E2E_IMAGE_REGISTRY):$(VERSION) .
 
 
 stop-kind: ## Stop kind cluster
 stop-kind: ## Stop kind cluster
 	kind delete cluster \
 	kind delete cluster \

+ 3 - 12
e2e/e2e_test.go

@@ -17,7 +17,7 @@ import (
 	"testing"
 	"testing"
 
 
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/ginkgo/v2"
 	// nolint
 	// nolint
 	. "github.com/onsi/gomega"
 	. "github.com/onsi/gomega"
 
 
@@ -30,25 +30,16 @@ var _ = SynchronizedBeforeSuite(func() []byte {
 	cfg := &addon.Config{}
 	cfg := &addon.Config{}
 	cfg.KubeConfig, cfg.KubeClientSet, cfg.CRClient = util.NewConfig()
 	cfg.KubeConfig, cfg.KubeClientSet, cfg.CRClient = util.NewConfig()
 
 
-	By("installing localstack")
-	addon.InstallGlobalAddon(addon.NewLocalstack(), cfg)
-
-	By("waiting for localstack")
-	err := util.WaitForURL("http://localstack.default/health")
-	Expect(err).ToNot(HaveOccurred())
-
 	By("installing eso")
 	By("installing eso")
 	addon.InstallGlobalAddon(addon.NewESO(), cfg)
 	addon.InstallGlobalAddon(addon.NewESO(), cfg)
 
 
-	By("installing scoped eso")
-	addon.InstallGlobalAddon(addon.NewScopedESO(), cfg)
 	return nil
 	return nil
 }, func([]byte) {})
 }, func([]byte) {})
 
 
 var _ = SynchronizedAfterSuite(func() {}, func() {
 var _ = SynchronizedAfterSuite(func() {}, func() {
 	By("Cleaning up global addons")
 	By("Cleaning up global addons")
 	addon.UninstallGlobalAddons()
 	addon.UninstallGlobalAddons()
-	if CurrentGinkgoTestDescription().Failed {
+	if CurrentSpecReport().Failed() {
 		addon.PrintLogs()
 		addon.PrintLogs()
 	}
 	}
 })
 })
@@ -56,5 +47,5 @@ var _ = SynchronizedAfterSuite(func() {}, func() {
 func TestE2E(t *testing.T) {
 func TestE2E(t *testing.T) {
 	NewWithT(t)
 	NewWithT(t)
 	RegisterFailHandler(Fail)
 	RegisterFailHandler(Fail)
-	RunSpecs(t, "external-secrets e2e suite")
+	RunSpecs(t, "external-secrets e2e suite", Label("e2e"))
 }
 }

+ 6 - 9
e2e/entrypoint.sh

@@ -19,8 +19,6 @@ set -euo pipefail
 NC='\e[0m'
 NC='\e[0m'
 BGREEN='\e[32m'
 BGREEN='\e[32m'
 
 
-SLOW_E2E_THRESHOLD=${SLOW_E2E_THRESHOLD:-50}
-FOCUS=${FOCUS:-.*}
 E2E_NODES=${E2E_NODES:-5}
 E2E_NODES=${E2E_NODES:-5}
 
 
 if [ ! -f "${HOME}/.kube/config" ]; then
 if [ ! -f "${HOME}/.kube/config" ]; then
@@ -31,13 +29,13 @@ if [ ! -f "${HOME}/.kube/config" ]; then
 fi
 fi
 
 
 ginkgo_args=(
 ginkgo_args=(
-  "-randomizeSuites"
-  "-randomizeAllSpecs"
-  "-flakeAttempts=2"
+  "--randomize-suites"
+  "--randomize-all"
+  "--flake-attempts=2"
   "-p"
   "-p"
   "-progress"
   "-progress"
   "-trace"
   "-trace"
-  "-slowSpecThreshold=${SLOW_E2E_THRESHOLD}"
+  "--slow-spec-threshold=5m"
   "-r"
   "-r"
   "-v"
   "-v"
   "-timeout=45m"
   "-timeout=45m"
@@ -45,9 +43,8 @@ ginkgo_args=(
 
 
 kubectl apply -f /k8s/deploy/crds
 kubectl apply -f /k8s/deploy/crds
 
 
-echo -e "${BGREEN}Running e2e test suite (FOCUS=${FOCUS})...${NC}"
+echo -e "${BGREEN}Running e2e test suite (LABELS=${GINKGO_LABELS})...${NC}"
 ACK_GINKGO_RC=true ginkgo "${ginkgo_args[@]}" \
 ACK_GINKGO_RC=true ginkgo "${ginkgo_args[@]}" \
-  -focus="${FOCUS}"                           \
-  -skip="\[Serial\]|\[MemoryLeak\]"           \
+  -label-filter="${GINKGO_LABELS}"            \
   -nodes="${E2E_NODES}"                       \
   -nodes="${E2E_NODES}"                       \
   /e2e.test
   /e2e.test

+ 1 - 1
e2e/framework/addon/addon.go

@@ -14,7 +14,7 @@ limitations under the License.
 package addon
 package addon
 
 
 import (
 import (
-	"github.com/onsi/ginkgo"
+	"github.com/onsi/ginkgo/v2"
 	"github.com/onsi/gomega"
 	"github.com/onsi/gomega"
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/rest"
 	"k8s.io/client-go/rest"

+ 1 - 1
e2e/framework/addon/chart.go

@@ -63,7 +63,7 @@ func (c *HelmChart) Install() error {
 
 
 	args := []string{"install", c.ReleaseName, c.Chart,
 	args := []string{"install", c.ReleaseName, c.Chart,
 		"--wait",
 		"--wait",
-		"--timeout", "600s",
+		"--timeout", "120s",
 		"--namespace", c.Namespace,
 		"--namespace", c.Namespace,
 	}
 	}
 
 

+ 64 - 57
e2e/framework/addon/eso.go

@@ -14,92 +14,99 @@ limitations under the License.
 package addon
 package addon
 
 
 import (
 import (
-	"fmt"
 	"os"
 	"os"
 
 
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo"
-	// nolint
-	. "github.com/onsi/gomega"
-
-	// nolint
-	"github.com/external-secrets/external-secrets/e2e/framework/util"
+	. "github.com/onsi/ginkgo/v2"
 )
 )
 
 
 type ESO struct {
 type ESO struct {
-	Addon
+	*HelmChart
 }
 }
 
 
-func NewESO() *ESO {
-	return &ESO{
+func NewESO(mutators ...MutationFunc) *ESO {
+	eso := &ESO{
 		&HelmChart{
 		&HelmChart{
 			Namespace:   "default",
 			Namespace:   "default",
 			ReleaseName: "eso",
 			ReleaseName: "eso",
 			Chart:       "/k8s/deploy/charts/external-secrets",
 			Chart:       "/k8s/deploy/charts/external-secrets",
-			Values:      []string{"/k8s/eso.values.yaml"},
+			Vars: []StringTuple{
+				{
+					Key:   "image.repository",
+					Value: os.Getenv("IMAGE_REGISTRY"),
+				},
+				{
+					Key:   "image.tag",
+					Value: os.Getenv("VERSION"),
+				},
+				{
+					Key:   "installCRDs",
+					Value: "false",
+				},
+			},
 		},
 		},
 	}
 	}
-}
 
 
-func (l *ESO) Install() error {
-	By("Installing eso\n")
-	err := l.Addon.Install()
-	if err != nil {
-		return err
+	for _, f := range mutators {
+		f(eso)
 	}
 	}
 
 
-	By("afterInstall eso\n")
-	err = l.afterInstall()
-	if err != nil {
-		return err
-	}
+	return eso
+}
 
 
-	return nil
+type MutationFunc func(eso *ESO)
+
+func WithReleaseName(name string) MutationFunc {
+	return func(eso *ESO) {
+		eso.HelmChart.ReleaseName = name
+	}
 }
 }
 
 
-func (l *ESO) afterInstall() error {
-	err := gcpPreparation()
-	Expect(err).NotTo(HaveOccurred())
-	err = awsPreparation()
-	Expect(err).NotTo(HaveOccurred())
-	if err != nil {
-		return err
+func WithNamespace(namespace string) MutationFunc {
+	return func(eso *ESO) {
+		eso.HelmChart.Namespace = namespace
 	}
 	}
-	return nil
 }
 }
 
 
-func gcpPreparation() error {
-	gcpProjectID := os.Getenv("GCP_PROJECT_ID")
-	gcpGSAName := os.Getenv("GCP_GSA_NAME")
-	gcpKSAName := os.Getenv("GCP_KSA_NAME")
-	_, kubeClientSet, _ := util.NewConfig()
+func WithNamespaceScope(namespace string) MutationFunc {
+	return func(eso *ESO) {
+		eso.HelmChart.Vars = append(eso.HelmChart.Vars, StringTuple{
+			Key:   "scopedNamespace",
+			Value: namespace,
+		})
+	}
+}
 
 
-	annotations := make(map[string]string)
-	annotations["iam.gke.io/gcp-service-account"] = fmt.Sprintf("%s@%s.iam.gserviceaccount.com", gcpGSAName, gcpProjectID)
-	_, err := util.UpdateKubeSA(gcpKSAName, kubeClientSet, "default", annotations)
-	Expect(err).NotTo(HaveOccurred())
+func WithServiceAccount(saName string) MutationFunc {
+	return func(eso *ESO) {
+		eso.HelmChart.Vars = append(eso.HelmChart.Vars, []StringTuple{
+			{
+				Key:   "serviceAccount.create",
+				Value: "false",
+			},
+			{
+				Key:   "serviceAccount.name",
+				Value: "eso-e2e-test",
+			},
+		}...)
+	}
+}
 
 
-	_, err = util.UpdateKubeSA("external-secrets-e2e", kubeClientSet, "default", annotations)
-	Expect(err).NotTo(HaveOccurred())
+func WithControllerClass(class string) MutationFunc {
+	return func(eso *ESO) {
+		eso.HelmChart.Vars = append(eso.HelmChart.Vars, StringTuple{
+			Key:   "extraArgs.controller-class",
+			Value: class,
+		})
+	}
+}
 
 
+func (l *ESO) Install() error {
+	By("Installing eso\n")
+	err := l.HelmChart.Install()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	return nil
 	return nil
 }
 }
-
-func awsPreparation() error {
-	return nil
-}
-
-func NewScopedESO() *ESO {
-	return &ESO{
-		&HelmChart{
-			Namespace:   "default",
-			ReleaseName: "eso-aws-sm",
-			Chart:       "/k8s/deploy/charts/external-secrets",
-			Values:      []string{"/k8s/eso.scoped.values.yaml"},
-		},
-	}
-}

+ 0 - 44
e2e/framework/addon/localstack.go

@@ -1,44 +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 addon
-
-import "github.com/external-secrets/external-secrets/e2e/framework/util"
-
-type Localstack struct {
-	Addon
-}
-
-func NewLocalstack() *Localstack {
-	return &Localstack{
-		&HelmChart{
-			Namespace:    "default",
-			ReleaseName:  "localstack",
-			Chart:        "localstack-charts/localstack",
-			ChartVersion: "0.2.0",
-			Repo: ChartRepo{
-				Name: "localstack-charts",
-				URL:  "https://localstack.github.io/helm-charts",
-			},
-			Values: []string{"/k8s/localstack.values.yaml"},
-		},
-	}
-}
-
-func (l *Localstack) Install() error {
-	err := l.Addon.Install()
-	if err != nil {
-		return err
-	}
-	return util.WaitForURL("http://localstack.default/health")
-}

+ 1 - 1
e2e/framework/addon/vault.go

@@ -32,7 +32,7 @@ import (
 	vault "github.com/hashicorp/vault/api"
 	vault "github.com/hashicorp/vault/api"
 
 
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/ginkgo/v2"
 	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"
 
 

+ 1 - 1
e2e/framework/eso.go

@@ -33,7 +33,7 @@ import (
 // with the provided values.
 // with the provided values.
 func (f *Framework) WaitForSecretValue(namespace, name string, expected *v1.Secret) (*v1.Secret, error) {
 func (f *Framework) WaitForSecretValue(namespace, name string, expected *v1.Secret) (*v1.Secret, error) {
 	secret := &v1.Secret{}
 	secret := &v1.Secret{}
-	err := wait.PollImmediate(time.Second*2, time.Minute*2, func() (bool, error) {
+	err := wait.PollImmediate(time.Second*5, time.Minute, func() (bool, error) {
 		err := f.CRClient.Get(context.Background(), types.NamespacedName{
 		err := f.CRClient.Get(context.Background(), types.NamespacedName{
 			Namespace: namespace,
 			Namespace: namespace,
 			Name:      name,
 			Name:      name,

+ 7 - 10
e2e/framework/framework.go

@@ -16,12 +16,10 @@ package framework
 import (
 import (
 
 
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/ginkgo/v2"
 
 
 	// nolint
 	// nolint
 	. "github.com/onsi/gomega"
 	. "github.com/onsi/gomega"
-	// nolint
-	. "github.com/onsi/ginkgo/extensions/table"
 	api "k8s.io/api/core/v1"
 	api "k8s.io/api/core/v1"
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/kubernetes"
 	kscheme "k8s.io/client-go/kubernetes/scheme"
 	kscheme "k8s.io/client-go/kubernetes/scheme"
@@ -30,6 +28,7 @@ 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/e2e/framework/addon"
 	"github.com/external-secrets/external-secrets/e2e/framework/addon"
+	"github.com/external-secrets/external-secrets/e2e/framework/log"
 	"github.com/external-secrets/external-secrets/e2e/framework/util"
 	"github.com/external-secrets/external-secrets/e2e/framework/util"
 )
 )
 
 
@@ -72,11 +71,9 @@ func New(baseName string) *Framework {
 // BeforeEach creates a namespace.
 // BeforeEach creates a namespace.
 func (f *Framework) BeforeEach() {
 func (f *Framework) BeforeEach() {
 	var err error
 	var err error
-	By("Building a namespace api object")
 	f.Namespace, err = util.CreateKubeNamespace(f.BaseName, f.KubeClientSet)
 	f.Namespace, err = util.CreateKubeNamespace(f.BaseName, f.KubeClientSet)
-	Expect(err).NotTo(HaveOccurred())
-
-	By("Using the namespace " + f.Namespace.Name)
+	log.Logf("created test namespace %s", f.Namespace.Name)
+	Expect(err).ToNot(HaveOccurred())
 }
 }
 
 
 // AfterEach deletes the namespace and cleans up the registered addons.
 // AfterEach deletes the namespace and cleans up the registered addons.
@@ -87,7 +84,7 @@ func (f *Framework) AfterEach() {
 	}
 	}
 	// reset addons to default once the run is done
 	// reset addons to default once the run is done
 	f.Addons = []addon.Addon{}
 	f.Addons = []addon.Addon{}
-	By("deleting test namespace")
+	log.Logf("deleting test namespace %s", f.Namespace.Name)
 	err := util.DeleteKubeNamespace(f.Namespace.Name, f.KubeClientSet)
 	err := util.DeleteKubeNamespace(f.Namespace.Name, f.KubeClientSet)
 	Expect(err).NotTo(HaveOccurred())
 	Expect(err).NotTo(HaveOccurred())
 }
 }
@@ -111,13 +108,13 @@ func (f *Framework) Install(a addon.Addon) {
 func Compose(descAppend string, f *Framework, fn func(f *Framework) (string, func(*TestCase)), tweaks ...func(*TestCase)) TableEntry {
 func Compose(descAppend string, f *Framework, fn func(f *Framework) (string, func(*TestCase)), tweaks ...func(*TestCase)) TableEntry {
 	desc, tfn := fn(f)
 	desc, tfn := fn(f)
 	tweaks = append(tweaks, tfn)
 	tweaks = append(tweaks, tfn)
-	te := Entry(desc + " " + descAppend)
 
 
 	// need to convert []func to []interface{}
 	// need to convert []func to []interface{}
 	ifs := make([]interface{}, len(tweaks))
 	ifs := make([]interface{}, len(tweaks))
 	for i := 0; i < len(tweaks); i++ {
 	for i := 0; i < len(tweaks); i++ {
 		ifs[i] = tweaks[i]
 		ifs[i] = tweaks[i]
 	}
 	}
-	te.Parameters = ifs
+	te := Entry(desc+" "+descAppend, ifs...)
+
 	return te
 	return te
 }
 }

+ 2 - 4
e2e/framework/log/log.go

@@ -14,12 +14,10 @@ limitations under the License.
 package log
 package log
 
 
 import (
 import (
-	"fmt"
-
-	"github.com/onsi/ginkgo"
+	"github.com/onsi/ginkgo/v2"
 )
 )
 
 
 // Logf logs the format string to ginkgo stdout.
 // Logf logs the format string to ginkgo stdout.
 func Logf(format string, args ...interface{}) {
 func Logf(format string, args ...interface{}) {
-	fmt.Fprintf(ginkgo.GinkgoWriter, format, args...)
+	ginkgo.GinkgoWriter.Printf(format, args)
 }
 }

+ 13 - 9
e2e/framework/util/util.go

@@ -22,9 +22,7 @@ import (
 	"time"
 	"time"
 
 
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo"
-	// nolint
-	. "github.com/onsi/gomega"
+	. "github.com/onsi/ginkgo/v2"
 	v1 "k8s.io/api/core/v1"
 	v1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -242,19 +240,25 @@ func NewConfig() (*restclient.Config, *kubernetes.Clientset, crclient.Client) {
 	kcPath := os.Getenv("KUBECONFIG")
 	kcPath := os.Getenv("KUBECONFIG")
 	if kcPath != "" {
 	if kcPath != "" {
 		kubeConfig, err = clientcmd.BuildConfigFromFlags("", kcPath)
 		kubeConfig, err = clientcmd.BuildConfigFromFlags("", kcPath)
-		Expect(err).NotTo(HaveOccurred())
+		if err != nil {
+			Fail(err.Error())
+		}
 	} else {
 	} else {
 		kubeConfig, err = restclient.InClusterConfig()
 		kubeConfig, err = restclient.InClusterConfig()
-		Expect(err).NotTo(HaveOccurred())
+		if err != nil {
+			Fail(err.Error())
+		}
 	}
 	}
 
 
-	By("creating a kubernetes client")
 	kubeClientSet, err := kubernetes.NewForConfig(kubeConfig)
 	kubeClientSet, err := kubernetes.NewForConfig(kubeConfig)
-	Expect(err).NotTo(HaveOccurred())
+	if err != nil {
+		Fail(err.Error())
+	}
 
 
-	By("creating a controller-runtime client")
 	CRClient, err := crclient.New(kubeConfig, crclient.Options{Scheme: Scheme})
 	CRClient, err := crclient.New(kubeConfig, crclient.Options{Scheme: Scheme})
-	Expect(err).NotTo(HaveOccurred())
+	if err != nil {
+		Fail(err.Error())
+	}
 
 
 	return kubeConfig, kubeClientSet, CRClient
 	return kubeConfig, kubeClientSet, CRClient
 }
 }

+ 0 - 12
e2e/k8s/eso.scoped.values.yaml

@@ -1,12 +0,0 @@
-installCRDs: false
-image:
-  repository: local/external-secrets
-  tag: test
-scopedNamespace: test
-extraEnv:
-  - name: AWS_SECRETSMANAGER_ENDPOINT
-    value: "http://localstack.default"
-  - name: AWS_STS_ENDPOINT
-    value: "http://localstack.default"
-  - name: AWS_SSM_ENDPOINT
-    value: "http://localstack.default"

+ 0 - 11
e2e/k8s/eso.values.yaml

@@ -1,11 +0,0 @@
-installCRDs: false
-image:
-  repository: local/external-secrets
-  tag: test
-extraEnv:
-  - name: AWS_SECRETSMANAGER_ENDPOINT
-    value: "http://localstack.default"
-  - name: AWS_STS_ENDPOINT
-    value: "http://localstack.default"
-  - name: AWS_SSM_ENDPOINT
-    value: "http://localstack.default"

+ 12 - 8
e2e/run.sh

@@ -42,20 +42,22 @@ done
 
 
 kubectl apply -f ${DIR}/k8s/deploy/crds
 kubectl apply -f ${DIR}/k8s/deploy/crds
 
 
-echo -e "Starting the e2e test pod"
+echo -e "Starting the e2e test pod ${E2E_IMAGE_REGISTRY}:${VERSION}"
 
 
 kubectl run --rm \
 kubectl run --rm \
   --attach \
   --attach \
   --restart=Never \
   --restart=Never \
-  --pod-running-timeout=10m \
-  --env="FOCUS=${FOCUS:-.*}" \
+  --pod-running-timeout=5m \
+  --env="GINKGO_LABELS=${GINKGO_LABELS:-.*}" \
   --env="GCP_SM_SA_JSON=${GCP_SM_SA_JSON:-}" \
   --env="GCP_SM_SA_JSON=${GCP_SM_SA_JSON:-}" \
   --env="GCP_PROJECT_ID=${GCP_PROJECT_ID:-}" \
   --env="GCP_PROJECT_ID=${GCP_PROJECT_ID:-}" \
-  --env="TF_VAR_GCP_PROJECT_ID=${TF_VAR_GCP_PROJECT_ID:-}" \
   --env="GCP_GSA_NAME=${GCP_GSA_NAME:-}" \
   --env="GCP_GSA_NAME=${GCP_GSA_NAME:-}" \
-  --env="GCP_KSA_NAME=${GCP_KSA_NAME:-}" \
-  --env="TF_VAR_GCP_GSA_NAME=${TF_VAR_GCP_GSA_NAME:-}" \
-  --env="TF_VAR_GCP_KSA_NAME=${TF_VAR_GCP_KSA_NAME:-}" \
+  --env="GCP_GKE_ZONE=${GCP_GKE_ZONE:-}" \
+  --env="GCP_GKE_CLUSTER=${GCP_GKE_CLUSTER:-}" \
+  --env="AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-}" \
+  --env="AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-}" \
+  --env="AWS_SA_NAME=${AWS_SA_NAME:-}" \
+  --env="AWS_SA_NAMESPACE=${AWS_SA_NAMESPACE:-}" \
   --env="AZURE_CLIENT_ID=${AZURE_CLIENT_ID:-}" \
   --env="AZURE_CLIENT_ID=${AZURE_CLIENT_ID:-}" \
   --env="AZURE_CLIENT_SECRET=${AZURE_CLIENT_SECRET:-}" \
   --env="AZURE_CLIENT_SECRET=${AZURE_CLIENT_SECRET:-}" \
   --env="AKEYLESS_ACCESS_ID=${AKEYLESS_ACCESS_ID:-}" \
   --env="AKEYLESS_ACCESS_ID=${AKEYLESS_ACCESS_ID:-}" \
@@ -70,5 +72,7 @@ kubectl run --rm \
   --env="ORACLE_REGION=${ORACLE_REGION:-}" \
   --env="ORACLE_REGION=${ORACLE_REGION:-}" \
   --env="ORACLE_FINGERPRINT=${ORACLE_FINGERPRINT:-}" \
   --env="ORACLE_FINGERPRINT=${ORACLE_FINGERPRINT:-}" \
   --env="ORACLE_KEY=${ORACLE_KEY:-}" \
   --env="ORACLE_KEY=${ORACLE_KEY:-}" \
+  --env="IMAGE_REGISTRY=${IMAGE_REGISTRY}" \
+  --env="VERSION=${VERSION}" \
   --overrides='{ "apiVersion": "v1", "spec":{"serviceAccountName": "external-secrets-e2e"}}' \
   --overrides='{ "apiVersion": "v1", "spec":{"serviceAccountName": "external-secrets-e2e"}}' \
-  e2e --image=${E2E_IMAGE_REGISTRY}:${E2E_VERSION}
+  e2e --image=${E2E_IMAGE_REGISTRY}:${VERSION}

+ 4 - 8
e2e/suite/akeyless/akeyless.go

@@ -15,23 +15,19 @@ limitations under the License.
 package akeyless
 package akeyless
 
 
 import (
 import (
-	"os"
 
 
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/ginkgo/v2"
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo/extensions/table"
+	. "github.com/onsi/ginkgo/v2/extensions/table"
 
 
 	"github.com/external-secrets/external-secrets/e2e/framework"
 	"github.com/external-secrets/external-secrets/e2e/framework"
 	"github.com/external-secrets/external-secrets/e2e/suite/common"
 	"github.com/external-secrets/external-secrets/e2e/suite/common"
 )
 )
 
 
-var _ = Describe("[akeyless] ", func() {
+var _ = Describe("[akeyless]", Label("akeyless"), func() {
 	f := framework.New("eso-akeyless")
 	f := framework.New("eso-akeyless")
-	accessID := os.Getenv("AKEYLESS_ACCESS_ID")
-	accessType := os.Getenv("AKEYLESS_ACCESS_TYPE")
-	accessTypeParam := os.Getenv("AKEYLESS_ACCESS_TYPE_PARAM")
-	prov := newAkeylessProvider(f, accessID, accessType, accessTypeParam)
+	prov := newFromEnv(f)
 
 
 	DescribeTable("sync secrets", framework.TableFunc(f, prov),
 	DescribeTable("sync secrets", framework.TableFunc(f, prov),
 		Entry(common.SimpleDataSync(f)),
 		Entry(common.SimpleDataSync(f)),

+ 8 - 1
e2e/suite/akeyless/provider.go

@@ -29,7 +29,7 @@ import (
 	"github.com/akeylesslabs/akeyless-go/v2"
 	"github.com/akeylesslabs/akeyless-go/v2"
 
 
 	//nolint
 	//nolint
-	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/ginkgo/v2"
 
 
 	//nolint
 	//nolint
 	. "github.com/onsi/gomega"
 	. "github.com/onsi/gomega"
@@ -75,6 +75,13 @@ func newAkeylessProvider(f *framework.Framework, accessID, accessType, accessTyp
 	return prov
 	return prov
 }
 }
 
 
+func newFromEnv(f *framework.Framework) *akeylessProvider {
+	accessID := os.Getenv("AKEYLESS_ACCESS_ID")
+	accessType := os.Getenv("AKEYLESS_ACCESS_TYPE")
+	accessTypeParam := os.Getenv("AKEYLESS_ACCESS_TYPE_PARAM")
+	return newAkeylessProvider(f, accessID, accessType, accessTypeParam)
+}
+
 // CreateSecret creates a secret.
 // CreateSecret creates a secret.
 func (a *akeylessProvider) CreateSecret(key, val string) {
 func (a *akeylessProvider) CreateSecret(key, val string) {
 	token, err := a.GetToken()
 	token, err := a.GetToken()

+ 4 - 12
e2e/suite/alibaba/alibaba.go

@@ -15,27 +15,19 @@ limitations under the License.
 package alibaba
 package alibaba
 
 
 import (
 import (
-	"os"
 
 
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/ginkgo/v2"
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo/extensions/table"
+	. "github.com/onsi/ginkgo/v2/extensions/table"
 
 
 	"github.com/external-secrets/external-secrets/e2e/framework"
 	"github.com/external-secrets/external-secrets/e2e/framework"
 	"github.com/external-secrets/external-secrets/e2e/suite/common"
 	"github.com/external-secrets/external-secrets/e2e/suite/common"
 )
 )
 
 
-var _ = Describe("[alibaba] ", func() {
+var _ = Describe("[alibaba]", Label("alibaba"), func() {
 	f := framework.New("eso-alibaba")
 	f := framework.New("eso-alibaba")
-	accessKeyID := os.Getenv("ACCESS_KEY_ID")
-	accessKeySecret := os.Getenv("ACCESS_KEY_SECRET")
-	regionID := os.Getenv("REGION_ID")
-	prov := &alibabaProvider{}
-
-	if accessKeyID != "" && accessKeySecret != "" && regionID != "" {
-		prov = newAlibabaProvider(f, accessKeyID, accessKeySecret, regionID)
-	}
+	prov := newFromEnv(f)
 
 
 	DescribeTable("sync secrets", framework.TableFunc(f, prov),
 	DescribeTable("sync secrets", framework.TableFunc(f, prov),
 		Entry(common.SimpleDataSync(f)),
 		Entry(common.SimpleDataSync(f)),

+ 9 - 1
e2e/suite/alibaba/provider.go

@@ -16,11 +16,12 @@ package alibaba
 
 
 import (
 import (
 	"context"
 	"context"
+	"os"
 
 
 	"github.com/aliyun/alibaba-cloud-sdk-go/services/kms"
 	"github.com/aliyun/alibaba-cloud-sdk-go/services/kms"
 
 
 	//nolint
 	//nolint
-	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/ginkgo/v2"
 
 
 	//nolint
 	//nolint
 	. "github.com/onsi/gomega"
 	. "github.com/onsi/gomega"
@@ -54,6 +55,13 @@ func newAlibabaProvider(f *framework.Framework, accessKeyID, accessKeySecret, re
 	return prov
 	return prov
 }
 }
 
 
+func newFromEnv(f *framework.Framework) *alibabaProvider {
+	accessKeyID := os.Getenv("ACCESS_KEY_ID")
+	accessKeySecret := os.Getenv("ACCESS_KEY_SECRET")
+	regionID := os.Getenv("REGION_ID")
+	return newAlibabaProvider(f, accessKeyID, accessKeySecret, regionID)
+}
+
 // CreateSecret creates a secret in both kv v1 and v2 provider.
 // CreateSecret creates a secret in both kv v1 and v2 provider.
 func (s *alibabaProvider) CreateSecret(key, val string) {
 func (s *alibabaProvider) CreateSecret(key, val string) {
 	client, err := kms.NewClientWithAccessKey(s.regionID, s.accessKeyID, s.accessKeySecret)
 	client, err := kms.NewClientWithAccessKey(s.regionID, s.accessKeyID, s.accessKeySecret)

+ 150 - 33
e2e/suite/aws/provider.go

@@ -16,6 +16,8 @@ package aws
 
 
 import (
 import (
 	"context"
 	"context"
+	"os"
+	"time"
 
 
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws/credentials"
 	"github.com/aws/aws-sdk-go/aws/credentials"
@@ -23,79 +25,194 @@ import (
 	"github.com/aws/aws-sdk-go/service/secretsmanager"
 	"github.com/aws/aws-sdk-go/service/secretsmanager"
 
 
 	//nolint
 	//nolint
-	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/ginkgo/v2"
 
 
 	// nolint
 	// nolint
 	. "github.com/onsi/gomega"
 	. "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"
+	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
 
 
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
-	esmeta "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/pkg/provider/aws/auth"
+	"github.com/external-secrets/external-secrets/e2e/framework/log"
 )
 )
 
 
 type SMProvider struct {
 type SMProvider struct {
-	url       string
+	ServiceAccountName      string
+	ServiceAccountNamespace string
+
+	kid       string
+	sak       string
+	region    string
 	client    *secretsmanager.SecretsManager
 	client    *secretsmanager.SecretsManager
 	framework *framework.Framework
 	framework *framework.Framework
 }
 }
 
 
-const secretName = "provider-secret"
+const (
+	staticCredentialsSecretName = "provider-secret"
+)
 
 
-func newSMProvider(f *framework.Framework, url string) *SMProvider {
+func NewSMProvider(f *framework.Framework, kid, sak, region, saName, saNamespace string) *SMProvider {
 	sess, err := session.NewSessionWithOptions(session.Options{
 	sess, err := session.NewSessionWithOptions(session.Options{
 		Config: aws.Config{
 		Config: aws.Config{
-			Credentials: credentials.NewStaticCredentials("foobar", "foobar", "secret-manager"),
-			EndpointResolver: auth.ResolveEndpointWithServiceMap(map[string]string{
-				"secretsmanager": url,
-			}),
-			Region: aws.String("eu-east-1"),
+			Credentials: credentials.NewStaticCredentials(kid, sak, ""),
+			Region:      aws.String(region),
 		},
 		},
 	})
 	})
-	Expect(err).ToNot(HaveOccurred())
+	if err != nil {
+		Fail(err.Error())
+	}
 	sm := secretsmanager.New(sess)
 	sm := secretsmanager.New(sess)
 	prov := &SMProvider{
 	prov := &SMProvider{
-		url:       url,
-		client:    sm,
-		framework: f,
+		ServiceAccountName:      saName,
+		ServiceAccountNamespace: saNamespace,
+		kid:                     kid,
+		sak:                     sak,
+		region:                  region,
+		client:                  sm,
+		framework:               f,
 	}
 	}
-	BeforeEach(prov.BeforeEach)
+
+	BeforeEach(func() {
+		prov.SetupStaticStore()
+		prov.SetupReferencedIRSAStore()
+		prov.SetupMountedIRSAStore()
+	})
+
+	AfterEach(func() {
+		// Cleanup ClusterSecretStore
+		err := prov.framework.CRClient.Delete(context.Background(), &esv1alpha1.ClusterSecretStore{
+			ObjectMeta: metav1.ObjectMeta{
+				Name: prov.ReferencedIRSAStoreName(),
+			},
+		})
+		Expect(err).ToNot(HaveOccurred())
+	})
+
 	return prov
 	return prov
 }
 }
 
 
+func NewFromEnv(f *framework.Framework) *SMProvider {
+	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 NewSMProvider(f, kid, sak, region, saName, saNamespace)
+}
+
+// CreateSecret creates a secret at the provider.
 func (s *SMProvider) CreateSecret(key, val string) {
 func (s *SMProvider) CreateSecret(key, val string) {
-	_, err := s.client.CreateSecret(&secretsmanager.CreateSecretInput{
-		Name:         aws.String(key),
-		SecretString: aws.String(val),
-	})
-	Expect(err).ToNot(HaveOccurred())
+	// 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
+	// we have to retry creating the secret
+	attempts := 20
+	for {
+		log.Logf("creating secret %s / attempts left: %d", key, attempts)
+		_, err := s.client.CreateSecret(&secretsmanager.CreateSecretInput{
+			Name:         aws.String(key),
+			SecretString: aws.String(val),
+		})
+		if err == nil {
+			return
+		}
+		attempts--
+		if attempts < 0 {
+			Fail("unable to create secret: " + err.Error())
+		}
+		<-time.After(time.Second * 5)
+	}
 }
 }
 
 
+// DeleteSecret deletes a secret at the provider.
+// There may be a short delay between calling this function
+// and the removal of the secret on the provider side.
 func (s *SMProvider) DeleteSecret(key string) {
 func (s *SMProvider) DeleteSecret(key string) {
+	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),
+		ForceDeleteWithoutRecovery: aws.Bool(true),
 	})
 	})
 	Expect(err).ToNot(HaveOccurred())
 	Expect(err).ToNot(HaveOccurred())
 }
 }
 
 
-func (s *SMProvider) BeforeEach() {
-	By("creating a AWS SM credentials secret")
+// MountedIRSAStore is a SecretStore without auth config
+// ESO relies on the pod-mounted ServiceAccount when using this store.
+func (s *SMProvider) SetupMountedIRSAStore() {
+	secretStore := &esv1alpha1.SecretStore{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      s.MountedIRSAStoreName(),
+			Namespace: s.framework.Namespace.Name,
+		},
+		Spec: esv1alpha1.SecretStoreSpec{
+			Provider: &esv1alpha1.SecretStoreProvider{
+				AWS: &esv1alpha1.AWSProvider{
+					Service: esv1alpha1.AWSServiceSecretsManager,
+					Region:  s.region,
+					Auth:    esv1alpha1.AWSAuth{},
+				},
+			},
+		},
+	}
+	err := s.framework.CRClient.Create(context.Background(), secretStore)
+	Expect(err).ToNot(HaveOccurred())
+}
+
+func (s *SMProvider) MountedIRSAStoreName() string {
+	return "irsa-mounted-" + s.framework.Namespace.Name
+}
+
+// ReferncedIRSAStore is a ClusterStore
+// that references a (IRSA-) ServiceAccount in the default namespace.
+func (s *SMProvider) SetupReferencedIRSAStore() {
+	log.Logf("creating IRSA ClusterSecretStore %s", s.framework.Namespace.Name)
+	secretStore := &esv1alpha1.ClusterSecretStore{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: s.ReferencedIRSAStoreName(),
+		},
+	}
+	_, err := controllerutil.CreateOrUpdate(context.Background(), s.framework.CRClient, secretStore, func() error {
+		secretStore.Spec.Provider = &esv1alpha1.SecretStoreProvider{
+			AWS: &esv1alpha1.AWSProvider{
+				Service: esv1alpha1.AWSServiceSecretsManager,
+				Region:  s.region,
+				Auth: esv1alpha1.AWSAuth{
+					JWTAuth: &esv1alpha1.AWSJWTAuth{
+						ServiceAccountRef: &esmetav1.ServiceAccountSelector{
+							Name:      s.ServiceAccountName,
+							Namespace: &s.ServiceAccountNamespace,
+						},
+					},
+				},
+			},
+		}
+		return nil
+	})
+	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{
 	awsCreds := &v1.Secret{
 		ObjectMeta: metav1.ObjectMeta{
 		ObjectMeta: metav1.ObjectMeta{
-			Name:      secretName,
+			Name:      staticCredentialsSecretName,
 			Namespace: s.framework.Namespace.Name,
 			Namespace: s.framework.Namespace.Name,
 		},
 		},
 		StringData: map[string]string{
 		StringData: map[string]string{
-			"kid": "foobar",
-			"sak": "foobar",
+			"kid": s.kid,
+			"sak": s.sak,
 		},
 		},
 	}
 	}
 	err := s.framework.CRClient.Create(context.Background(), awsCreds)
 	err := s.framework.CRClient.Create(context.Background(), awsCreds)
 	Expect(err).ToNot(HaveOccurred())
 	Expect(err).ToNot(HaveOccurred())
 
 
-	By("creating a AWS SM secret store")
 	secretStore := &esv1alpha1.SecretStore{
 	secretStore := &esv1alpha1.SecretStore{
 		ObjectMeta: metav1.ObjectMeta{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      s.framework.Namespace.Name,
 			Name:      s.framework.Namespace.Name,
@@ -105,15 +222,15 @@ func (s *SMProvider) BeforeEach() {
 			Provider: &esv1alpha1.SecretStoreProvider{
 			Provider: &esv1alpha1.SecretStoreProvider{
 				AWS: &esv1alpha1.AWSProvider{
 				AWS: &esv1alpha1.AWSProvider{
 					Service: esv1alpha1.AWSServiceSecretsManager,
 					Service: esv1alpha1.AWSServiceSecretsManager,
-					Region:  "us-east-1",
+					Region:  s.region,
 					Auth: esv1alpha1.AWSAuth{
 					Auth: esv1alpha1.AWSAuth{
 						SecretRef: &esv1alpha1.AWSAuthSecretRef{
 						SecretRef: &esv1alpha1.AWSAuthSecretRef{
-							AccessKeyID: esmeta.SecretKeySelector{
-								Name: secretName,
+							AccessKeyID: esmetav1.SecretKeySelector{
+								Name: staticCredentialsSecretName,
 								Key:  "kid",
 								Key:  "kid",
 							},
 							},
-							SecretAccessKey: esmeta.SecretKeySelector{
-								Name: secretName,
+							SecretAccessKey: esmetav1.SecretKeySelector{
+								Name: staticCredentialsSecretName,
 								Key:  "sak",
 								Key:  "sak",
 							},
 							},
 						},
 						},

+ 4 - 91
e2e/suite/aws/secretsmanager.go

@@ -15,103 +15,17 @@ limitations under the License.
 package aws
 package aws
 
 
 import (
 import (
-	"context"
-	"fmt"
 
 
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/ginkgo/v2"
 
 
-	// nolint
-	. "github.com/onsi/ginkgo/extensions/table"
-
-	// nolint
-	. "github.com/onsi/gomega"
-	v1 "k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-
-	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
-	esmeta "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/suite/common"
 	"github.com/external-secrets/external-secrets/e2e/suite/common"
 )
 )
 
 
-var _ = Describe("[aws] ", func() {
-	f := framework.New("eso-aws")
-	prov := newSMProvider(f, "http://localstack.default")
-
-	jwt := func(tc *framework.TestCase) {
-		saName := "my-sa"
-		err := f.CRClient.Create(context.Background(), &v1.ServiceAccount{
-			ObjectMeta: metav1.ObjectMeta{
-				Name:      saName,
-				Namespace: f.Namespace.Name,
-				Annotations: map[string]string{
-					"eks.amazonaws.com/role-arn": "arn:aws:iam::account:role/my-example-role",
-				},
-			},
-		})
-		Expect(err).ToNot(HaveOccurred())
-
-		// create secret store
-		secretStore := &esv1alpha1.SecretStore{
-			TypeMeta: metav1.TypeMeta{
-				Kind:       esv1alpha1.SecretStoreKind,
-				APIVersion: esv1alpha1.SchemeGroupVersion.String(),
-			},
-			ObjectMeta: metav1.ObjectMeta{
-				Name:      f.Namespace.Name,
-				Namespace: f.Namespace.Name,
-			},
-			Spec: esv1alpha1.SecretStoreSpec{
-				Provider: &esv1alpha1.SecretStoreProvider{
-					AWS: &esv1alpha1.AWSProvider{
-						Service: esv1alpha1.AWSServiceSecretsManager,
-						Region:  "us-east-1",
-						Auth: esv1alpha1.AWSAuth{
-							JWTAuth: &esv1alpha1.AWSJWTAuth{
-								ServiceAccountRef: &esmeta.ServiceAccountSelector{
-									Name:      saName,
-									Namespace: &f.Namespace.Name,
-								},
-							},
-						},
-					},
-				},
-			},
-		}
-		err = f.CRClient.Patch(context.Background(), secretStore, client.Apply, client.FieldOwner("e2e-case"), client.ForceOwnership)
-		Expect(err).ToNot(HaveOccurred())
-
-		secretKey1 := fmt.Sprintf("%s-%s", f.Namespace.Name, "one")
-		secretKey2 := fmt.Sprintf("%s-%s", f.Namespace.Name, "other")
-		secretValue := "bar"
-		tc.Secrets = map[string]string{
-			secretKey1: secretValue,
-			secretKey2: secretValue,
-		}
-		tc.ExpectedSecret = &v1.Secret{
-			Type: v1.SecretTypeOpaque,
-			Data: map[string][]byte{
-				secretKey1: []byte(secretValue),
-				secretKey2: []byte(secretValue),
-			},
-		}
-		tc.ExternalSecret.Spec.Data = []esv1alpha1.ExternalSecretData{
-			{
-				SecretKey: secretKey1,
-				RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
-					Key: secretKey1,
-				},
-			},
-			{
-				SecretKey: secretKey2,
-				RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
-					Key: secretKey2,
-				},
-			},
-		}
-	}
+var _ = Describe("[aws] ", Label("aws", "secretsmanager"), func() {
+	f := framework.New("eso-aws-sm")
+	prov := NewFromEnv(f)
 
 
 	DescribeTable("sync secrets",
 	DescribeTable("sync secrets",
 		framework.TableFunc(f,
 		framework.TableFunc(f,
@@ -121,7 +35,6 @@ var _ = Describe("[aws] ", func() {
 		Entry(common.JSONDataFromSync(f)),
 		Entry(common.JSONDataFromSync(f)),
 		Entry(common.JSONDataWithProperty(f)),
 		Entry(common.JSONDataWithProperty(f)),
 		Entry(common.JSONDataWithTemplate(f)),
 		Entry(common.JSONDataWithTemplate(f)),
-		Entry("should sync secrets with jwt auth", jwt),
 		Entry(common.DockerJSONConfig(f)),
 		Entry(common.DockerJSONConfig(f)),
 		Entry(common.DataPropertyDockerconfigJSON(f)),
 		Entry(common.DataPropertyDockerconfigJSON(f)),
 		Entry(common.SSHKeySync(f)),
 		Entry(common.SSHKeySync(f)),

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

@@ -0,0 +1,102 @@
+/*
+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()
+	}
+}

+ 3 - 14
e2e/suite/azure/azure.go

@@ -13,28 +13,17 @@ limitations under the License.
 package azure
 package azure
 
 
 import (
 import (
-	"os"
 
 
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo"
-	// nolint
-	. "github.com/onsi/ginkgo/extensions/table"
+	. "github.com/onsi/ginkgo/v2"
 
 
 	"github.com/external-secrets/external-secrets/e2e/framework"
 	"github.com/external-secrets/external-secrets/e2e/framework"
 	"github.com/external-secrets/external-secrets/e2e/suite/common"
 	"github.com/external-secrets/external-secrets/e2e/suite/common"
 )
 )
 
 
-var _ = Describe("[azure] ", func() {
+var _ = Describe("[azure]", Label("azure", "keyvault"), func() {
 	f := framework.New("eso-azure")
 	f := framework.New("eso-azure")
-	vaultURL := os.Getenv("VAULT_URL")
-	tenantID := os.Getenv("TENANT_ID")
-	clientID := os.Getenv("AZURE_CLIENT_ID")
-	clientSecret := os.Getenv("AZURE_CLIENT_SECRET")
-	prov := &azureProvider{}
-
-	if vaultURL != "" && tenantID != "" && clientID != "" && clientSecret != "" {
-		prov = newazureProvider(f, clientID, clientSecret, tenantID, vaultURL)
-	}
+	prov := newFromEnv(f)
 
 
 	DescribeTable("sync secrets", framework.TableFunc(f, prov),
 	DescribeTable("sync secrets", framework.TableFunc(f, prov),
 		Entry(common.SimpleDataSync(f)),
 		Entry(common.SimpleDataSync(f)),

+ 21 - 5
e2e/suite/azure/provider.go

@@ -14,15 +14,17 @@ package azure
 
 
 import (
 import (
 	"context"
 	"context"
+	"os"
 
 
 	"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
 	// nolint
-	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
 
 
 	// nolint
 	// nolint
-	. "github.com/onsi/gomega"
+	. "github.com/onsi/ginkgo/v2"
+
 	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"
@@ -45,7 +47,9 @@ func newazureProvider(f *framework.Framework, clientID, clientSecret, tenantID,
 	clientCredentialsConfig := kvauth.NewClientCredentialsConfig(clientID, clientSecret, tenantID)
 	clientCredentialsConfig := kvauth.NewClientCredentialsConfig(clientID, clientSecret, tenantID)
 	clientCredentialsConfig.Resource = "https://vault.azure.net"
 	clientCredentialsConfig.Resource = "https://vault.azure.net"
 	authorizer, err := clientCredentialsConfig.Authorizer()
 	authorizer, err := clientCredentialsConfig.Authorizer()
-	Expect(err).ToNot(HaveOccurred())
+	if err != nil {
+		Fail(err.Error())
+	}
 	basicClient := keyvault.New()
 	basicClient := keyvault.New()
 	basicClient.Authorizer = authorizer
 	basicClient.Authorizer = authorizer
 
 
@@ -57,10 +61,22 @@ func newazureProvider(f *framework.Framework, clientID, clientSecret, tenantID,
 		vaultURL:     vaultURL,
 		vaultURL:     vaultURL,
 		client:       &basicClient,
 		client:       &basicClient,
 	}
 	}
-	BeforeEach(prov.BeforeEach)
+
+	BeforeEach(func() {
+		prov.CreateSecretStore()
+	})
+
 	return prov
 	return prov
 }
 }
 
 
+func newFromEnv(f *framework.Framework) *azureProvider {
+	vaultURL := os.Getenv("VAULT_URL")
+	tenantID := os.Getenv("TENANT_ID")
+	clientID := os.Getenv("AZURE_CLIENT_ID")
+	clientSecret := os.Getenv("AZURE_CLIENT_SECRET")
+	return newazureProvider(f, clientID, clientSecret, tenantID, vaultURL)
+}
+
 func (s *azureProvider) CreateSecret(key, val string) {
 func (s *azureProvider) CreateSecret(key, val string) {
 	_, err := s.client.SetSecret(
 	_, err := s.client.SetSecret(
 		context.Background(),
 		context.Background(),
@@ -84,7 +100,7 @@ func (s *azureProvider) DeleteSecret(key string) {
 	Expect(err).ToNot(HaveOccurred())
 	Expect(err).ToNot(HaveOccurred())
 }
 }
 
 
-func (s *azureProvider) BeforeEach() {
+func (s *azureProvider) CreateSecretStore() {
 	azureCreds := &v1.Secret{
 	azureCreds := &v1.Secret{
 		ObjectMeta: metav1.ObjectMeta{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      "provider-secret",
 			Name:      "provider-secret",

+ 55 - 63
e2e/suite/gcp/gcp.go

@@ -17,12 +17,9 @@ import (
 	"crypto/x509"
 	"crypto/x509"
 	"encoding/pem"
 	"encoding/pem"
 	"fmt"
 	"fmt"
-	"os"
 
 
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo"
-	// nolint
-	. "github.com/onsi/ginkgo/extensions/table"
+	. "github.com/onsi/ginkgo/v2"
 	v1 "k8s.io/api/core/v1"
 	v1 "k8s.io/api/core/v1"
 	p12 "software.sslmate.com/src/go-pkcs12"
 	p12 "software.sslmate.com/src/go-pkcs12"
 
 
@@ -32,21 +29,32 @@ import (
 	"github.com/external-secrets/external-secrets/e2e/suite/common"
 	"github.com/external-secrets/external-secrets/e2e/suite/common"
 )
 )
 
 
-var _ = Describe("[gcp] ", func() {
+// This test uses the global ESO.
+var _ = Describe("[gcp]", Label("gcp", "secretsmanager"), func() {
 	f := framework.New("eso-gcp")
 	f := framework.New("eso-gcp")
-	credentials := os.Getenv("GCP_SM_SA_JSON")
-	projectID := os.Getenv("GCP_PROJECT_ID")
-	prov := &GcpProvider{}
+	prov := NewFromEnv(f, "")
 
 
-	if credentials != "" && projectID != "" {
-		prov = NewgcpProvider(f, credentials, projectID, "", "", "", "")
-	}
+	DescribeTable("sync secrets", framework.TableFunc(f, prov),
+		Entry(common.SimpleDataSync(f)),
+		Entry(common.JSONDataWithProperty(f)),
+		Entry(common.JSONDataFromSync(f)),
+		Entry(common.NestedJSONWithGJSON(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)),
+		Entry("should sync p12 encoded cert secret", p12Cert),
+	)
+})
 
 
-	// P12Cert case creates a secret with a p12 cert containing a privkey and cert bundled together.
-	// It uses templating to generate a k8s secret of type tls with pem values
-	p12Cert := func(tc *framework.TestCase) {
-		cloudSecretName := fmt.Sprintf("%s-%s", f.Namespace.Name, "p12-cert-example")
-		certPEM := `-----BEGIN CERTIFICATE-----
+// P12Cert case creates a secret with a p12 cert containing a privkey and cert bundled together.
+// It uses templating to generate a k8s secret of type tls with pem values.
+var p12Cert = func(tc *framework.TestCase) {
+	cloudSecretName := fmt.Sprintf("%s-%s", tc.Framework.Namespace.Name, "p12-cert-example")
+	certPEM := `-----BEGIN CERTIFICATE-----
 MIIFQjCCBCqgAwIBAgISBHszg5W2maz/7CIxGrf7mqukMA0GCSqGSIb3DQEBCwUA
 MIIFQjCCBCqgAwIBAgISBHszg5W2maz/7CIxGrf7mqukMA0GCSqGSIb3DQEBCwUA
 MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
 MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
 EwJSMzAeFw0yMTA3MjQxMjQyMzNaFw0yMTEwMjIxMjQyMzFaMCgxJjAkBgNVBAMT
 EwJSMzAeFw0yMTA3MjQxMjQyMzNaFw0yMTEwMjIxMjQyMzFaMCgxJjAkBgNVBAMT
@@ -78,7 +86,7 @@ XMYitHfpGhc+DTTiTWMQ13J0b1j4yv8A7ZaG2366aa28oSTD6eQFhmVCBwa54j++
 IOwzHn5R
 IOwzHn5R
 -----END CERTIFICATE-----
 -----END CERTIFICATE-----
 `
 `
-		privkeyPEM := `-----BEGIN PRIVATE KEY-----
+	privkeyPEM := `-----BEGIN PRIVATE KEY-----
 MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDJFE51myQDyqca
 MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDJFE51myQDyqca
 egyBDlHLkxVj+WCjcfOWEqrTa7bcnbDXjD4uIRTaFxIkpi/k5fKxt+rszna7bNdh
 egyBDlHLkxVj+WCjcfOWEqrTa7bcnbDXjD4uIRTaFxIkpi/k5fKxt+rszna7bNdh
 lezqSuRBmVg2kXDul5nQm1RtWRKlJP9fhvUYkoNKRGzt9OL6/6lv05P2tNu13yN8
 lezqSuRBmVg2kXDul5nQm1RtWRKlJP9fhvUYkoNKRGzt9OL6/6lv05P2tNu13yN8
@@ -107,55 +115,39 @@ Jdx0ECYawviQoreDAyIXV6HouoeRbDtLZ9AJvxMoIjGcjAR2FQHc3yx4h/lf3Tfx
 x6HaRh+EUwU51von6M9lEF9/p5Q=
 x6HaRh+EUwU51von6M9lEF9/p5Q=
 -----END PRIVATE KEY-----
 -----END PRIVATE KEY-----
 `
 `
-		blockCert, _ := pem.Decode([]byte(certPEM))
-		cert, _ := x509.ParseCertificate(blockCert.Bytes)
-		blockPrivKey, _ := pem.Decode([]byte(privkeyPEM))
-		privkey, _ := x509.ParsePKCS8PrivateKey(blockPrivKey.Bytes)
-		emptyCACerts := []*x509.Certificate{}
-		p12Cert, _ := p12.Encode(rand.Reader, privkey, cert, emptyCACerts, "")
+	blockCert, _ := pem.Decode([]byte(certPEM))
+	cert, _ := x509.ParseCertificate(blockCert.Bytes)
+	blockPrivKey, _ := pem.Decode([]byte(privkeyPEM))
+	privkey, _ := x509.ParsePKCS8PrivateKey(blockPrivKey.Bytes)
+	emptyCACerts := []*x509.Certificate{}
+	p12Cert, _ := p12.Encode(rand.Reader, privkey, cert, emptyCACerts, "")
 
 
-		tc.Secrets = map[string]string{
-			cloudSecretName: string(p12Cert),
-		}
-
-		tc.ExpectedSecret = &v1.Secret{
-			Type: v1.SecretTypeTLS,
-			Data: map[string][]byte{
-				"tls.crt": []byte(certPEM),
-				"tls.key": []byte(privkeyPEM),
-			},
-		}
+	tc.Secrets = map[string]string{
+		cloudSecretName: string(p12Cert),
+	}
 
 
-		tc.ExternalSecret.Spec.Data = []esv1alpha1.ExternalSecretData{
-			{
-				SecretKey: "mysecret",
-				RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
-					Key: cloudSecretName,
-				},
-			},
-		}
+	tc.ExpectedSecret = &v1.Secret{
+		Type: v1.SecretTypeTLS,
+		Data: map[string][]byte{
+			"tls.crt": []byte(certPEM),
+			"tls.key": []byte(privkeyPEM),
+		},
+	}
 
 
-		tc.ExternalSecret.Spec.Target.Template = &esv1alpha1.ExternalSecretTemplate{
-			Type: v1.SecretTypeTLS,
-			Data: map[string]string{
-				"tls.crt": "{{ .mysecret | pkcs12cert | pemCertificate }}",
-				"tls.key": "{{ .mysecret | pkcs12key | pemPrivateKey }}",
+	tc.ExternalSecret.Spec.Data = []esv1alpha1.ExternalSecretData{
+		{
+			SecretKey: "mysecret",
+			RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
+				Key: cloudSecretName,
 			},
 			},
-		}
+		},
 	}
 	}
 
 
-	DescribeTable("sync secrets", framework.TableFunc(f, prov),
-		Entry(common.SimpleDataSync(f)),
-		Entry(common.JSONDataWithProperty(f)),
-		Entry(common.JSONDataFromSync(f)),
-		Entry(common.NestedJSONWithGJSON(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)),
-		Entry("should sync p12 encoded cert secret", p12Cert),
-	)
-})
+	tc.ExternalSecret.Spec.Target.Template = &esv1alpha1.ExternalSecretTemplate{
+		Type: v1.SecretTypeTLS,
+		Data: map[string]string{
+			"tls.crt": "{{ .mysecret | pkcs12cert | pemCertificate }}",
+			"tls.key": "{{ .mysecret | pkcs12key | pemPrivateKey }}",
+		},
+	}
+}

+ 111 - 0
e2e/suite/gcp/gcp_managed.go

@@ -0,0 +1,111 @@
+/*
+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 gcp
+
+import (
+
+	// nolint
+	. "github.com/onsi/ginkgo/v2"
+
+	// nolint
+	// . "github.com/onsi/gomega"
+	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 (
+	withPodID     = "sync secrets with pod identity"
+	withSpecifcSA = "sync secrets with specificSA identity"
+)
+
+// Deploys eso to the default namespace
+// that uses the service account provisioned by terraform
+// to test pod-identity authentication.
+var _ = Describe("[gcpmanaged] with pod identity", Label("gcp", "secretsmanager", "managed", "pod-identity"), func() {
+	f := framework.New("eso-gcpmanaged")
+	prov := NewFromEnv(f, f.BaseName)
+
+	// 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),
+		// uses pod id
+		framework.Compose(withPodID, f, common.SimpleDataSync, usePodIDESReference),
+		framework.Compose(withPodID, f, common.JSONDataWithProperty, usePodIDESReference),
+		framework.Compose(withPodID, f, common.JSONDataFromSync, usePodIDESReference),
+		framework.Compose(withPodID, f, common.NestedJSONWithGJSON, usePodIDESReference),
+		framework.Compose(withPodID, f, common.JSONDataWithTemplate, usePodIDESReference),
+		framework.Compose(withPodID, f, common.DockerJSONConfig, usePodIDESReference),
+		framework.Compose(withPodID, f, common.DataPropertyDockerconfigJSON, usePodIDESReference),
+		framework.Compose(withPodID, f, common.SSHKeySync, usePodIDESReference),
+		framework.Compose(withPodID, f, common.SSHKeySyncDataProperty, usePodIDESReference),
+		framework.Compose(withPodID, f, common.SyncWithoutTargetName, usePodIDESReference),
+		framework.Compose(withPodID, f, common.JSONDataWithoutTargetName, usePodIDESReference),
+	)
+})
+
+// We're using a namespace scoped ESO
+// that runs WITHOUT pod identity (with default sa)
+// It uses a specific service account defined in the ClusterSecretStore spec
+// to authenticate against cloud provider APIs.
+var _ = Describe("[gcpmanaged] with service account", Label("gcp", "secretsmanager", "managed", "service-account"), func() {
+	f := framework.New("eso-gcpmanaged")
+	prov := NewFromEnv(f, f.BaseName)
+
+	BeforeEach(func() {
+		f.Install(addon.NewESO(
+			addon.WithControllerClass(f.BaseName),
+			addon.WithReleaseName(f.Namespace.Name),
+			addon.WithNamespace(f.Namespace.Name),
+		))
+	})
+
+	DescribeTable("sync secrets",
+		framework.TableFunc(f,
+			prov),
+		// uses specific sa
+		framework.Compose(withSpecifcSA, f, common.JSONDataFromSync, useSpecifcSAESReference(prov)),
+		framework.Compose(withSpecifcSA, f, common.JSONDataWithProperty, useSpecifcSAESReference(prov)),
+		framework.Compose(withSpecifcSA, f, common.JSONDataFromSync, useSpecifcSAESReference(prov)),
+		framework.Compose(withSpecifcSA, f, common.NestedJSONWithGJSON, useSpecifcSAESReference(prov)),
+		framework.Compose(withSpecifcSA, f, common.JSONDataWithTemplate, useSpecifcSAESReference(prov)),
+		framework.Compose(withSpecifcSA, f, common.DockerJSONConfig, useSpecifcSAESReference(prov)),
+		framework.Compose(withSpecifcSA, f, common.DataPropertyDockerconfigJSON, useSpecifcSAESReference(prov)),
+		framework.Compose(withSpecifcSA, f, common.SSHKeySync, useSpecifcSAESReference(prov)),
+		framework.Compose(withSpecifcSA, f, common.SSHKeySyncDataProperty, useSpecifcSAESReference(prov)),
+		framework.Compose(withSpecifcSA, f, common.SyncWithoutTargetName, useSpecifcSAESReference(prov)),
+		framework.Compose(withSpecifcSA, f, common.JSONDataWithoutTargetName, useSpecifcSAESReference(prov)),
+	)
+})
+
+func usePodIDESReference(tc *framework.TestCase) {
+	tc.ExternalSecret.Spec.SecretStoreRef.Name = PodIDSecretStoreName
+}
+
+func useSpecifcSAESReference(prov *GcpProvider) func(*framework.TestCase) {
+	return func(tc *framework.TestCase) {
+		tc.ExternalSecret.Spec.SecretStoreRef.Kind = esv1alpha1.ClusterSecretStoreKind
+		tc.ExternalSecret.Spec.SecretStoreRef.Name = prov.SAClusterSecretStoreName()
+	}
+}

+ 107 - 101
e2e/suite/gcp/provider.go

@@ -15,116 +15,97 @@ package gcp
 import (
 import (
 	"context"
 	"context"
 	"fmt"
 	"fmt"
+	"os"
 
 
 	secretmanager "cloud.google.com/go/secretmanager/apiv1"
 	secretmanager "cloud.google.com/go/secretmanager/apiv1"
 
 
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/ginkgo/v2"
 
 
 	// nolint
 	// nolint
 	. "github.com/onsi/gomega"
 	. "github.com/onsi/gomega"
-	"golang.org/x/oauth2"
 	"golang.org/x/oauth2/google"
 	"golang.org/x/oauth2/google"
 	"golang.org/x/oauth2/jwt"
 	"golang.org/x/oauth2/jwt"
 	"google.golang.org/api/option"
 	"google.golang.org/api/option"
 	secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1"
 	secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1"
 	v1 "k8s.io/api/core/v1"
 	v1 "k8s.io/api/core/v1"
-	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/types"
 	utilpointer "k8s.io/utils/pointer"
 	utilpointer "k8s.io/utils/pointer"
+	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
 
 
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
 	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
 	esmeta "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"
 	gcpsm "github.com/external-secrets/external-secrets/pkg/provider/gcp/secretmanager"
 	gcpsm "github.com/external-secrets/external-secrets/pkg/provider/gcp/secretmanager"
 )
 )
 
 
 const (
 const (
-	PodIDSecretStoreName     = "pod-identity"
-	SpecifcSASecretStoreName = "specific-sa"
+	PodIDSecretStoreName        = "pod-identity"
+	staticCredentialsSecretName = "provider-secret"
 )
 )
 
 
-func makeStore(s *GcpProvider) *esv1alpha1.SecretStore {
-	return &esv1alpha1.SecretStore{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      s.framework.Namespace.Name,
-			Namespace: s.framework.Namespace.Name,
-		},
-		Spec: esv1alpha1.SecretStoreSpec{
-			Provider: &esv1alpha1.SecretStoreProvider{
-				GCPSM: &esv1alpha1.GCPSMProvider{
-					ProjectID: s.projectID,
-				},
-			},
-		},
-	}
-}
-
-func makeCStore(s *GcpProvider) *esv1alpha1.ClusterSecretStore {
-	return &esv1alpha1.ClusterSecretStore{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      s.framework.Namespace.Name,
-			Namespace: s.framework.Namespace.Name,
-		},
-		Spec: esv1alpha1.SecretStoreSpec{
-			Provider: &esv1alpha1.SecretStoreProvider{
-				GCPSM: &esv1alpha1.GCPSMProvider{
-					ProjectID: s.projectID,
-				},
-			},
-		},
-	}
-}
-
 // nolint // Better to keep names consistent even if it stutters;
 // nolint // Better to keep names consistent even if it stutters;
 type GcpProvider struct {
 type GcpProvider struct {
-	credentials             string
-	projectID               string
-	framework               *framework.Framework
-	clusterLocation         string
-	clusterName             string
-	serviceAccountName      string
-	serviceAccountNamespace string
+	ServiceAccountName      string
+	ServiceAccountNamespace string
+
+	framework       *framework.Framework
+	credentials     string
+	projectID       string
+	clusterLocation string
+	clusterName     string
+	controllerClass string
 }
 }
 
 
-func NewgcpProvider(f *framework.Framework, credentials, projectID string,
-	clusterLocation string, clusterName string, serviceAccountName string, serviceAccountNamespace string) *GcpProvider {
+func NewGCPProvider(f *framework.Framework, credentials, projectID string,
+	clusterLocation string, clusterName string, serviceAccountName string, serviceAccountNamespace string, controllerClass string) *GcpProvider {
 	prov := &GcpProvider{
 	prov := &GcpProvider{
 		credentials:             credentials,
 		credentials:             credentials,
 		projectID:               projectID,
 		projectID:               projectID,
 		framework:               f,
 		framework:               f,
 		clusterLocation:         clusterLocation,
 		clusterLocation:         clusterLocation,
 		clusterName:             clusterName,
 		clusterName:             clusterName,
-		serviceAccountName:      serviceAccountName,
-		serviceAccountNamespace: serviceAccountNamespace,
+		ServiceAccountName:      serviceAccountName,
+		ServiceAccountNamespace: serviceAccountNamespace,
+		controllerClass:         controllerClass,
 	}
 	}
-	BeforeEach(prov.BeforeEach)
+
+	BeforeEach(func() {
+		prov.CreateSAKeyStore(f.Namespace.Name)
+		prov.CreateSpecifcSASecretStore(f.Namespace.Name)
+		prov.CreatePodIDStore(f.Namespace.Name)
+	})
+
+	AfterEach(func() {
+		prov.DeleteSpecifcSASecretStore()
+	})
+
 	return prov
 	return prov
 }
 }
 
 
-func (s *GcpProvider) getClient(ctx context.Context, credentials string) (client *secretmanager.Client, err error) {
-	if credentials == "" {
-		var ts oauth2.TokenSource
-		ts, err = google.DefaultTokenSource(ctx, gcpsm.CloudPlatformRole)
-		Expect(err).ToNot(HaveOccurred())
-		client, err = secretmanager.NewClient(ctx, option.WithTokenSource(ts))
-		Expect(err).ToNot(HaveOccurred())
-	} else {
-		var config *jwt.Config
-		config, err = google.JWTConfigFromJSON([]byte(s.credentials), gcpsm.CloudPlatformRole)
-		Expect(err).ToNot(HaveOccurred())
-		ts := config.TokenSource(ctx)
-		client, err = secretmanager.NewClient(ctx, option.WithTokenSource(ts))
-		Expect(err).ToNot(HaveOccurred())
-	}
+func NewFromEnv(f *framework.Framework, controllerClass string) *GcpProvider {
+	projectID := os.Getenv("GCP_PROJECT_ID")
+	credentials := os.Getenv("GCP_SM_SA_JSON")
+	serviceAccountName := os.Getenv("GCP_KSA_NAME")
+	serviceAccountNamespace := "default"
+	clusterLocation := os.Getenv("GCP_GKE_ZONE")
+	clusterName := os.Getenv("GCP_GKE_CLUSTER")
+	return NewGCPProvider(f, credentials, projectID, clusterLocation, clusterName, serviceAccountName, serviceAccountNamespace, controllerClass)
+}
+
+func (s *GcpProvider) getClient(ctx context.Context) (client *secretmanager.Client, err error) {
+	var config *jwt.Config
+	config, err = google.JWTConfigFromJSON([]byte(s.credentials), gcpsm.CloudPlatformRole)
+	Expect(err).ToNot(HaveOccurred())
+	ts := config.TokenSource(ctx)
+	client, err = secretmanager.NewClient(ctx, option.WithTokenSource(ts))
+	Expect(err).ToNot(HaveOccurred())
 	return client, err
 	return client, err
 }
 }
 
 
 func (s *GcpProvider) CreateSecret(key, val string) {
 func (s *GcpProvider) CreateSecret(key, val string) {
 	ctx := context.Background()
 	ctx := context.Background()
-	client, err := s.getClient(ctx, s.credentials)
+	client, err := s.getClient(ctx)
 	Expect(err).ToNot(HaveOccurred())
 	Expect(err).ToNot(HaveOccurred())
 	defer client.Close()
 	defer client.Close()
 	// Create the request to create the secret.
 	// Create the request to create the secret.
@@ -153,7 +134,7 @@ func (s *GcpProvider) CreateSecret(key, val string) {
 
 
 func (s *GcpProvider) DeleteSecret(key string) {
 func (s *GcpProvider) DeleteSecret(key string) {
 	ctx := context.Background()
 	ctx := context.Background()
-	client, err := s.getClient(ctx, s.credentials)
+	client, err := s.getClient(ctx)
 	Expect(err).ToNot(HaveOccurred())
 	Expect(err).ToNot(HaveOccurred())
 	Expect(err).ToNot(HaveOccurred())
 	Expect(err).ToNot(HaveOccurred())
 	defer client.Close()
 	defer client.Close()
@@ -164,11 +145,27 @@ func (s *GcpProvider) DeleteSecret(key string) {
 	Expect(err).ToNot(HaveOccurred())
 	Expect(err).ToNot(HaveOccurred())
 }
 }
 
 
-func (s *GcpProvider) BeforeEach() {
-	By("creating a gcp secret")
+func makeStore(s *GcpProvider) *esv1alpha1.SecretStore {
+	return &esv1alpha1.SecretStore{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      s.framework.Namespace.Name,
+			Namespace: s.framework.Namespace.Name,
+		},
+		Spec: esv1alpha1.SecretStoreSpec{
+			Controller: s.controllerClass,
+			Provider: &esv1alpha1.SecretStoreProvider{
+				GCPSM: &esv1alpha1.GCPSMProvider{
+					ProjectID: s.projectID,
+				},
+			},
+		},
+	}
+}
+
+func (s *GcpProvider) CreateSAKeyStore(ns string) {
 	gcpCreds := &v1.Secret{
 	gcpCreds := &v1.Secret{
 		ObjectMeta: metav1.ObjectMeta{
 		ObjectMeta: metav1.ObjectMeta{
-			Name:      "provider-secret",
+			Name:      staticCredentialsSecretName,
 			Namespace: s.framework.Namespace.Name,
 			Namespace: s.framework.Namespace.Name,
 		},
 		},
 		StringData: map[string]string{
 		StringData: map[string]string{
@@ -180,23 +177,16 @@ func (s *GcpProvider) BeforeEach() {
 		err = s.framework.CRClient.Update(context.Background(), gcpCreds)
 		err = s.framework.CRClient.Update(context.Background(), gcpCreds)
 		Expect(err).ToNot(HaveOccurred())
 		Expect(err).ToNot(HaveOccurred())
 	}
 	}
-	By("creating an secret stores gcp")
-	s.CreateSAKeyStore(s.framework.Namespace.Name)
-	s.CreatePodIDStore(s.framework.Namespace.Name)
-	s.CreateSpecifcSASecretStore(s.framework.Namespace.Name)
-}
-
-func (s *GcpProvider) CreateSAKeyStore(ns string) {
 	secretStore := makeStore(s)
 	secretStore := makeStore(s)
 	secretStore.Spec.Provider.GCPSM.Auth = esv1alpha1.GCPSMAuth{
 	secretStore.Spec.Provider.GCPSM.Auth = esv1alpha1.GCPSMAuth{
 		SecretRef: &esv1alpha1.GCPSMAuthSecretRef{
 		SecretRef: &esv1alpha1.GCPSMAuthSecretRef{
 			SecretAccessKey: esmeta.SecretKeySelector{
 			SecretAccessKey: esmeta.SecretKeySelector{
-				Name: "provider-secret",
+				Name: staticCredentialsSecretName,
 				Key:  "secret-access-credentials",
 				Key:  "secret-access-credentials",
 			},
 			},
 		},
 		},
 	}
 	}
-	err := s.framework.CRClient.Create(context.Background(), secretStore)
+	err = s.framework.CRClient.Create(context.Background(), secretStore)
 	Expect(err).ToNot(HaveOccurred())
 	Expect(err).ToNot(HaveOccurred())
 }
 }
 
 
@@ -207,29 +197,45 @@ func (s *GcpProvider) CreatePodIDStore(ns string) {
 	Expect(err).ToNot(HaveOccurred())
 	Expect(err).ToNot(HaveOccurred())
 }
 }
 
 
+func (s *GcpProvider) SAClusterSecretStoreName() string {
+	return "gcpsa-" + s.framework.Namespace.Name
+}
+
 func (s *GcpProvider) CreateSpecifcSASecretStore(ns string) {
 func (s *GcpProvider) CreateSpecifcSASecretStore(ns string) {
-	clusterSecretStore := makeCStore(s)
-	clusterSecretStore.ObjectMeta.Name = SpecifcSASecretStoreName
-	clusterSecretStore.Spec.Provider.GCPSM.Auth = esv1alpha1.GCPSMAuth{
-		WorkloadIdentity: &esv1alpha1.GCPWorkloadIdentity{
-			ClusterLocation: s.clusterLocation,
-			ClusterName:     s.clusterName,
-			ServiceAccountRef: esmeta.ServiceAccountSelector{
-				Name:      s.serviceAccountName,
-				Namespace: utilpointer.StringPtr(s.serviceAccountNamespace),
-			},
+	clusterSecretStore := &esv1alpha1.ClusterSecretStore{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: s.SAClusterSecretStoreName(),
 		},
 		},
 	}
 	}
+	_, err := controllerutil.CreateOrUpdate(context.Background(), s.framework.CRClient, clusterSecretStore, func() error {
+		clusterSecretStore.Spec.Controller = s.controllerClass
+		clusterSecretStore.Spec.Provider = &esv1alpha1.SecretStoreProvider{
+			GCPSM: &esv1alpha1.GCPSMProvider{
+				ProjectID: s.projectID,
+				Auth: esv1alpha1.GCPSMAuth{
+					WorkloadIdentity: &esv1alpha1.GCPWorkloadIdentity{
+						ClusterLocation: s.clusterLocation,
+						ClusterName:     s.clusterName,
+						ServiceAccountRef: esmeta.ServiceAccountSelector{
+							Name:      s.ServiceAccountName,
+							Namespace: utilpointer.StringPtr(s.ServiceAccountNamespace),
+						},
+					},
+				},
+			},
+		}
+		return nil
+	})
+	Expect(err).ToNot(HaveOccurred())
+}
 
 
-	var cSS esv1alpha1.ClusterSecretStore
-
-	err := s.framework.CRClient.Get(context.Background(), types.NamespacedName{
-		Name: SpecifcSASecretStoreName,
-	}, &cSS)
-	if apierrors.IsNotFound(err) {
-		err := s.framework.CRClient.Create(context.Background(), clusterSecretStore)
-		Expect(err).ToNot(HaveOccurred())
-	} else {
-		log.Logf("%s CSStore already created", SpecifcSASecretStoreName)
-	}
+// Cleanup removes global resources that may have been
+// created by this provider.
+func (s *GcpProvider) DeleteSpecifcSASecretStore() {
+	err := s.framework.CRClient.Delete(context.Background(), &esv1alpha1.ClusterSecretStore{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: s.SAClusterSecretStoreName(),
+		},
+	})
+	Expect(err).ToNot(HaveOccurred())
 }
 }

+ 0 - 86
e2e/suite/gcpmanaged/gcpmanaged.go

@@ -1,86 +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.
-limitations under the License.
-*/
-package gcpmanaged
-
-import (
-	"os"
-
-	// nolint
-	. "github.com/onsi/ginkgo"
-	// nolint
-	. "github.com/onsi/ginkgo/extensions/table"
-
-	// nolint
-	// . "github.com/onsi/gomega"
-	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/suite/common"
-	"github.com/external-secrets/external-secrets/e2e/suite/gcp"
-)
-
-const (
-	withPodID     = "sync secrets with pod identity"
-	withSpecifcSA = "sync secrets with specificSA identity"
-)
-
-var _ = Describe("[gcpmanaged] ", func() {
-	if os.Getenv("FOCUS") == "gcpmanaged" {
-		f := framework.New("eso-gcp-managed")
-		projectID := os.Getenv("GCP_PROJECT_ID")
-		clusterLocation := "europe-west1-b"
-		clusterName := "test-cluster"
-		serviceAccountName := os.Getenv("GCP_KSA_NAME")
-		serviceAccountNamespace := "default"
-		prov := &gcp.GcpProvider{}
-		if projectID != "" {
-			prov = gcp.NewgcpProvider(f, "", projectID, clusterLocation, clusterName, serviceAccountName, serviceAccountNamespace)
-		}
-		DescribeTable("sync secrets",
-			framework.TableFunc(f,
-				prov),
-			// uses pod id
-			framework.Compose(withPodID, f, common.SimpleDataSync, usePodIDESReference),
-			framework.Compose(withPodID, f, common.JSONDataWithProperty, usePodIDESReference),
-			framework.Compose(withPodID, f, common.JSONDataFromSync, usePodIDESReference),
-			framework.Compose(withPodID, f, common.NestedJSONWithGJSON, usePodIDESReference),
-			framework.Compose(withPodID, f, common.JSONDataWithTemplate, usePodIDESReference),
-			framework.Compose(withPodID, f, common.DockerJSONConfig, usePodIDESReference),
-			framework.Compose(withPodID, f, common.DataPropertyDockerconfigJSON, usePodIDESReference),
-			framework.Compose(withPodID, f, common.SSHKeySync, usePodIDESReference),
-			framework.Compose(withPodID, f, common.SSHKeySyncDataProperty, usePodIDESReference),
-			framework.Compose(withPodID, f, common.SyncWithoutTargetName, usePodIDESReference),
-			framework.Compose(withPodID, f, common.JSONDataWithoutTargetName, usePodIDESReference),
-			// uses specific sa
-			framework.Compose(withSpecifcSA, f, common.JSONDataFromSync, useSpecifcSAESReference),
-			framework.Compose(withSpecifcSA, f, common.JSONDataWithProperty, useSpecifcSAESReference),
-			framework.Compose(withSpecifcSA, f, common.JSONDataFromSync, useSpecifcSAESReference),
-			framework.Compose(withSpecifcSA, f, common.NestedJSONWithGJSON, useSpecifcSAESReference),
-			framework.Compose(withSpecifcSA, f, common.JSONDataWithTemplate, useSpecifcSAESReference),
-			framework.Compose(withSpecifcSA, f, common.DockerJSONConfig, useSpecifcSAESReference),
-			framework.Compose(withSpecifcSA, f, common.DataPropertyDockerconfigJSON, useSpecifcSAESReference),
-			framework.Compose(withSpecifcSA, f, common.SSHKeySync, useSpecifcSAESReference),
-			framework.Compose(withSpecifcSA, f, common.SSHKeySyncDataProperty, useSpecifcSAESReference),
-			framework.Compose(withSpecifcSA, f, common.SyncWithoutTargetName, useSpecifcSAESReference),
-			framework.Compose(withSpecifcSA, f, common.JSONDataWithoutTargetName, useSpecifcSAESReference),
-		)
-	}
-})
-
-func usePodIDESReference(tc *framework.TestCase) {
-	tc.ExternalSecret.Spec.SecretStoreRef.Name = gcp.PodIDSecretStoreName
-}
-
-func useSpecifcSAESReference(tc *framework.TestCase) {
-	tc.ExternalSecret.Spec.SecretStoreRef.Kind = esv1alpha1.ClusterSecretStoreKind
-	tc.ExternalSecret.Spec.SecretStoreRef.Name = gcp.SpecifcSASecretStoreName
-}

+ 5 - 13
e2e/suite/gitlab/gitlab.go

@@ -18,27 +18,19 @@ package gitlab
 // and in e2e/suite/common/common.go, but this breaks Azure provider.
 // and in e2e/suite/common/common.go, but this breaks Azure provider.
 
 
 import (
 import (
-	"os"
 
 
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/ginkgo/v2"
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo/extensions/table"
+	. "github.com/onsi/ginkgo/v2/extensions/table"
 
 
 	"github.com/external-secrets/external-secrets/e2e/framework"
 	"github.com/external-secrets/external-secrets/e2e/framework"
 	"github.com/external-secrets/external-secrets/e2e/suite/common"
 	"github.com/external-secrets/external-secrets/e2e/suite/common"
 )
 )
 
 
-var _ = Describe("[gitlab] ", func() {
-	f := framework.New("esogitlab")
-	credentials := os.Getenv("GITLAB_TOKEN")
-	projectID := os.Getenv("GITLAB_PROJECT_ID")
-
-	prov := &gitlabProvider{}
-
-	if credentials != "" && projectID != "" {
-		prov = newGitlabProvider(f, credentials, projectID)
-	}
+var _ = Describe("[gitlab]", Label("gitlab"), func() {
+	f := framework.New("eso-gitlab")
+	prov := newFromEnv(f)
 
 
 	DescribeTable("sync secrets", framework.TableFunc(f, prov),
 	DescribeTable("sync secrets", framework.TableFunc(f, prov),
 		Entry(common.SimpleDataSync(f)),
 		Entry(common.SimpleDataSync(f)),

+ 8 - 1
e2e/suite/gitlab/provider.go

@@ -15,10 +15,11 @@ package gitlab
 
 
 import (
 import (
 	"context"
 	"context"
+	"os"
 	"strings"
 	"strings"
 
 
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/ginkgo/v2"
 
 
 	// nolint
 	// nolint
 	. "github.com/onsi/gomega"
 	. "github.com/onsi/gomega"
@@ -47,6 +48,12 @@ func newGitlabProvider(f *framework.Framework, credentials, projectID string) *g
 	return prov
 	return prov
 }
 }
 
 
+func newFromEnv(f *framework.Framework) *gitlabProvider {
+	credentials := os.Getenv("GITLAB_TOKEN")
+	projectID := os.Getenv("GITLAB_PROJECT_ID")
+	return newGitlabProvider(f, credentials, projectID)
+}
+
 func (s *gitlabProvider) CreateSecret(key, val string) {
 func (s *gitlabProvider) CreateSecret(key, val string) {
 	// **Open the client
 	// **Open the client
 	client, err := gitlab.NewClient(s.credentials)
 	client, err := gitlab.NewClient(s.credentials)

+ 0 - 1
e2e/suite/import.go

@@ -19,6 +19,5 @@ import (
 	_ "github.com/external-secrets/external-secrets/e2e/suite/aws"
 	_ "github.com/external-secrets/external-secrets/e2e/suite/aws"
 	_ "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/gcpmanaged"
 	_ "github.com/external-secrets/external-secrets/e2e/suite/vault"
 	_ "github.com/external-secrets/external-secrets/e2e/suite/vault"
 )
 )

+ 4 - 10
e2e/suite/oracle/oracle.go

@@ -13,25 +13,19 @@ limitations under the License.
 package oracle
 package oracle
 
 
 import (
 import (
-	"os"
 
 
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/ginkgo/v2"
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo/extensions/table"
+	. "github.com/onsi/ginkgo/v2/extensions/table"
 
 
 	"github.com/external-secrets/external-secrets/e2e/framework"
 	"github.com/external-secrets/external-secrets/e2e/framework"
 	"github.com/external-secrets/external-secrets/e2e/suite/common"
 	"github.com/external-secrets/external-secrets/e2e/suite/common"
 )
 )
 
 
-var _ = Describe("[oracle] ", func() {
+var _ = Describe("[oracle]", Label("oracle"), func() {
 	f := framework.New("eso-oracle")
 	f := framework.New("eso-oracle")
-	tenancy := os.Getenv("OCI_TENANCY_OCID")
-	user := os.Getenv("OCI_USER_OCID")
-	region := os.Getenv("OCI_REGION")
-	fingerprint := os.Getenv("OCI_FINGERPRINT")
-	privateKey := os.Getenv("OCI_PRIVATE_KEY")
-	prov := newOracleProvider(f, tenancy, user, region, fingerprint, privateKey)
+	prov := newFromEnv(f)
 
 
 	DescribeTable("sync secrets", framework.TableFunc(f, prov),
 	DescribeTable("sync secrets", framework.TableFunc(f, prov),
 		Entry(common.SimpleDataSync(f)),
 		Entry(common.SimpleDataSync(f)),

+ 11 - 1
e2e/suite/oracle/provider.go

@@ -14,9 +14,10 @@ package oracle
 
 
 import (
 import (
 	"context"
 	"context"
+	"os"
 
 
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/ginkgo/v2"
 
 
 	// nolint
 	// nolint
 	. "github.com/onsi/gomega"
 	. "github.com/onsi/gomega"
@@ -58,6 +59,15 @@ func newOracleProvider(f *framework.Framework, tenancy, user, region, fingerprin
 	return prov
 	return prov
 }
 }
 
 
+func newFromEnv(f *framework.Framework) *oracleProvider {
+	tenancy := os.Getenv("OCI_TENANCY_OCID")
+	user := os.Getenv("OCI_USER_OCID")
+	region := os.Getenv("OCI_REGION")
+	fingerprint := os.Getenv("OCI_FINGERPRINT")
+	privateKey := os.Getenv("OCI_PRIVATE_KEY")
+	return newOracleProvider(f, tenancy, user, region, fingerprint, privateKey)
+}
+
 func (p *oracleProvider) CreateSecret(key, val string) {
 func (p *oracleProvider) CreateSecret(key, val string) {
 	configurationProvider := common.NewRawConfigurationProvider(p.tenancy, p.user, p.region, p.fingerprint, p.privateKey, nil)
 	configurationProvider := common.NewRawConfigurationProvider(p.tenancy, p.user, p.region, p.fingerprint, p.privateKey, nil)
 	client, err := vault.NewVaultsClientWithConfigurationProvider(configurationProvider)
 	client, err := vault.NewVaultsClientWithConfigurationProvider(configurationProvider)

+ 1 - 1
e2e/suite/vault/provider.go

@@ -21,7 +21,7 @@ import (
 	vault "github.com/hashicorp/vault/api"
 	vault "github.com/hashicorp/vault/api"
 
 
 	//nolint
 	//nolint
-	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/ginkgo/v2"
 
 
 	//nolint
 	//nolint
 	. "github.com/onsi/gomega"
 	. "github.com/onsi/gomega"

+ 4 - 6
e2e/suite/vault/vault.go

@@ -15,9 +15,7 @@ package vault
 import (
 import (
 
 
 	// nolint
 	// nolint
-	. "github.com/onsi/ginkgo"
-	// nolint
-	. "github.com/onsi/ginkgo/extensions/table"
+	. "github.com/onsi/ginkgo/v2"
 
 
 	"github.com/external-secrets/external-secrets/e2e/framework"
 	"github.com/external-secrets/external-secrets/e2e/framework"
 	"github.com/external-secrets/external-secrets/e2e/suite/common"
 	"github.com/external-secrets/external-secrets/e2e/suite/common"
@@ -32,12 +30,12 @@ const (
 	withK8s       = "with kubernetes provider"
 	withK8s       = "with kubernetes provider"
 )
 )
 
 
-var _ = Describe("[vault] ", func() {
+var _ = Describe("[vault]", Label("vault"), func() {
 	f := framework.New("eso-vault")
 	f := framework.New("eso-vault")
+	prov := newVaultProvider(f)
 
 
 	DescribeTable("sync secrets",
 	DescribeTable("sync secrets",
-		framework.TableFunc(f,
-			newVaultProvider(f)),
+		framework.TableFunc(f, prov),
 		// uses token auth
 		// uses token auth
 		framework.Compose(withTokenAuth, f, common.JSONDataFromSync, useTokenAuth),
 		framework.Compose(withTokenAuth, f, common.JSONDataFromSync, useTokenAuth),
 		framework.Compose(withTokenAuth, f, common.JSONDataWithProperty, useTokenAuth),
 		framework.Compose(withTokenAuth, f, common.JSONDataWithProperty, useTokenAuth),

+ 2 - 3
go.mod

@@ -57,7 +57,7 @@ require (
 	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 v1.16.5
+	github.com/onsi/ginkgo/v2 v2.0.0
 	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
@@ -133,6 +133,7 @@ require (
 	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.0.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/googleapis/gax-go/v2 v2.1.1 // 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
@@ -174,7 +175,6 @@ require (
 	github.com/moby/spdystream v0.2.0 // indirect
 	github.com/moby/spdystream v0.2.0 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
-	github.com/nxadm/tail v1.4.8 // indirect
 	github.com/oklog/run v1.1.0 // indirect
 	github.com/oklog/run v1.1.0 // indirect
 	github.com/oklog/ulid v1.3.1 // indirect
 	github.com/oklog/ulid v1.3.1 // indirect
 	github.com/pierrec/lz4 v2.6.1+incompatible // indirect
 	github.com/pierrec/lz4 v2.6.1+incompatible // indirect
@@ -211,7 +211,6 @@ require (
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	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/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // 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
 	honnef.co/go/tools v0.1.4 // indirect
 	k8s.io/apiextensions-apiserver v0.23.0 // indirect
 	k8s.io/apiextensions-apiserver v0.23.0 // indirect

+ 4 - 0
go.sum

@@ -412,8 +412,10 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
 github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
 github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -680,6 +682,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/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=

+ 1 - 1
main.go

@@ -56,7 +56,7 @@ func main() {
 			"Enabling this will ensure there is only one active controller manager.")
 			"Enabling this will ensure there is only one active controller manager.")
 	flag.IntVar(&concurrent, "concurrent", 1, "The number of concurrent ExternalSecret reconciles.")
 	flag.IntVar(&concurrent, "concurrent", 1, "The number of concurrent ExternalSecret reconciles.")
 	flag.StringVar(&loglevel, "loglevel", "info", "loglevel to use, one of: debug, info, warn, error, dpanic, panic, fatal")
 	flag.StringVar(&loglevel, "loglevel", "info", "loglevel to use, one of: debug, info, warn, error, dpanic, panic, fatal")
-	flag.StringVar(&namespace, "namespace", "", "watch external secrets scoped in the provided namespace only")
+	flag.StringVar(&namespace, "namespace", "", "watch external secrets scoped in the provided namespace only. ClusterSecretStore can be used but only work if it doesn't reference resources from other namespaces")
 	flag.Parse()
 	flag.Parse()
 
 
 	var lvl zapcore.Level
 	var lvl zapcore.Level

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

@@ -20,8 +20,7 @@ import (
 	"strconv"
 	"strconv"
 	"time"
 	"time"
 
 
-	. "github.com/onsi/ginkgo"
-	. "github.com/onsi/ginkgo/extensions/table"
+	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
 	. "github.com/onsi/gomega"
 	dto "github.com/prometheus/client_model/go"
 	dto "github.com/prometheus/client_model/go"
 	v1 "k8s.io/api/core/v1"
 	v1 "k8s.io/api/core/v1"

+ 2 - 2
pkg/controllers/externalsecret/suite_test.go

@@ -19,7 +19,7 @@ import (
 	"testing"
 	"testing"
 	"time"
 	"time"
 
 
-	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
 	. "github.com/onsi/gomega"
 	"go.uber.org/zap/zapcore"
 	"go.uber.org/zap/zapcore"
 	"k8s.io/client-go/kubernetes/scheme"
 	"k8s.io/client-go/kubernetes/scheme"
@@ -89,7 +89,7 @@ var _ = BeforeSuite(func() {
 		defer GinkgoRecover()
 		defer GinkgoRecover()
 		Expect(k8sManager.Start(ctrl.SetupSignalHandler())).ToNot(HaveOccurred())
 		Expect(k8sManager.Start(ctrl.SetupSignalHandler())).ToNot(HaveOccurred())
 	}()
 	}()
-}, 60)
+})
 
 
 var _ = AfterSuite(func() {
 var _ = AfterSuite(func() {
 	By("tearing down the test environment")
 	By("tearing down the test environment")

+ 2 - 2
pkg/controllers/secretstore/suite_test.go

@@ -18,7 +18,7 @@ import (
 	"path/filepath"
 	"path/filepath"
 	"testing"
 	"testing"
 
 
-	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
 	. "github.com/onsi/gomega"
 	"k8s.io/client-go/kubernetes/scheme"
 	"k8s.io/client-go/kubernetes/scheme"
 	"k8s.io/client-go/rest"
 	"k8s.io/client-go/rest"
@@ -65,7 +65,7 @@ var _ = BeforeSuite(func() {
 	k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
 	k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
 	Expect(err).ToNot(HaveOccurred())
 	Expect(err).ToNot(HaveOccurred())
 	Expect(k8sClient).ToNot(BeNil())
 	Expect(k8sClient).ToNot(BeNil())
-}, 60)
+})
 
 
 var _ = AfterSuite(func() {
 var _ = AfterSuite(func() {
 	By("tearing down the test environment")
 	By("tearing down the test environment")

+ 8 - 0
terraform/aws/main.tf

@@ -0,0 +1,8 @@
+module "cluster" {
+  source = "./modules/cluster"
+
+  cluster_name      = var.AWS_CLUSTER_NAME
+  cluster_region    = var.AWS_REGION
+  irsa_sa_name      = var.AWS_SA_NAME
+  irsa_sa_namespace = var.AWS_SA_NAMESPACE
+}

+ 60 - 0
terraform/aws/modules/cluster/auth.tf

@@ -0,0 +1,60 @@
+
+data "aws_eks_cluster_auth" "this" {
+  name = module.eks.cluster_id
+}
+
+data "aws_caller_identity" "current" {}
+
+locals {
+  kubeconfig = yamlencode({
+    apiVersion      = "v1"
+    kind            = "Config"
+    current-context = "terraform"
+    clusters = [{
+      name = module.eks.cluster_id
+      cluster = {
+        certificate-authority-data = module.eks.cluster_certificate_authority_data
+        server                     = module.eks.cluster_endpoint
+      }
+    }]
+    contexts = [{
+      name = "terraform"
+      context = {
+        cluster = module.eks.cluster_id
+        user    = "terraform"
+      }
+    }]
+    users = [{
+      name = "terraform"
+      user = {
+        token = data.aws_eks_cluster_auth.this.token
+      }
+    }]
+  })
+
+  # we have to allow the root account to access the api
+  aws_auth_configmap_yaml = <<-EOT
+  ${chomp(module.eks.aws_auth_configmap_yaml)}
+      - rolearn: arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/admin
+        username: system:aws:root
+        groups:
+          - system:masters
+  EOT
+}
+
+resource "null_resource" "patch_cm" {
+  triggers = {
+    kubeconfig = base64encode(local.kubeconfig)
+    cmd_patch  = <<-EOT
+      kubectl patch configmap/aws-auth --patch "${local.aws_auth_configmap_yaml}" -n kube-system --kubeconfig <(echo $KUBECONFIG | base64 --decode)
+    EOT
+  }
+
+  provisioner "local-exec" {
+    interpreter = ["/bin/bash", "-c"]
+    environment = {
+      KUBECONFIG = self.triggers.kubeconfig
+    }
+    command = self.triggers.cmd_patch
+  }
+}

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

@@ -0,0 +1,57 @@
+locals {
+  sa_manifest = <<-EOT
+      apiVersion: v1
+      kind: ServiceAccount
+      metadata:
+        name: ${local.serviceaccount_name}
+        namespace: ${local.serviceaccount_namespace}
+        annotations:
+          eks.amazonaws.com/role-arn: "${aws_iam_role.eso-e2e-irsa.arn}"
+  EOT
+}
+
+data "aws_iam_policy_document" "assume-policy" {
+  statement {
+    actions = ["sts:AssumeRoleWithWebIdentity"]
+    condition {
+      test     = "StringEquals"
+      variable = "${trimprefix(module.eks.cluster_oidc_issuer_url, "https://")}:sub"
+
+      values = [
+        "system:serviceaccount:${local.serviceaccount_namespace}:${local.serviceaccount_name}"
+      ]
+    }
+
+    principals {
+      type        = "Federated"
+      identifiers = [module.eks.oidc_provider_arn]
+    }
+  }
+}
+
+resource "aws_iam_role" "eso-e2e-irsa" {
+  name               = "eso-e2e-irsa"
+  path               = "/"
+  assume_role_policy = data.aws_iam_policy_document.assume-policy.json
+  managed_policy_arns = [
+    "arn:aws:iam::aws:policy/SecretsManagerReadWrite"
+  ]
+
+}
+
+resource "null_resource" "apply_sa" {
+  triggers = {
+    kubeconfig = base64encode(local.kubeconfig)
+    cmd_patch  = <<-EOT
+      echo '${local.sa_manifest}' | kubectl --kubeconfig <(echo $KUBECONFIG | base64 --decode) apply -f -
+    EOT
+  }
+
+  provisioner "local-exec" {
+    interpreter = ["/bin/bash", "-c"]
+    environment = {
+      KUBECONFIG = self.triggers.kubeconfig
+    }
+    command = self.triggers.cmd_patch
+  }
+}

+ 127 - 0
terraform/aws/modules/cluster/main.tf

@@ -0,0 +1,127 @@
+provider "aws" {
+  region = local.region
+}
+
+locals {
+  name            = var.cluster_name
+  cluster_version = "1.21"
+  region          = var.cluster_region
+
+  serviceaccount_name      = var.irsa_sa_name
+  serviceaccount_namespace = var.irsa_sa_namespace
+
+  tags = {
+    Example    = local.name
+    GithubRepo = "external-secrets"
+    GithubOrg  = "external-secrets"
+  }
+}
+
+module "eks" {
+  source = "git::https://github.com/terraform-aws-modules/terraform-aws-eks?ref=v18.2.0"
+
+  cluster_name                    = local.name
+  cluster_version                 = local.cluster_version
+  cluster_endpoint_private_access = true
+  cluster_endpoint_public_access  = true
+
+  cluster_addons = {
+    coredns = {
+      resolve_conflicts = "OVERWRITE"
+    }
+    kube-proxy = {}
+    vpc-cni = {
+      resolve_conflicts = "OVERWRITE"
+    }
+
+  }
+
+  vpc_id      = module.vpc.vpc_id
+  subnet_ids  = module.vpc.private_subnets
+  enable_irsa = true
+
+  # EKS Managed Node Group(s)
+  eks_managed_node_group_defaults = {
+    ami_type               = "AL2_x86_64"
+    disk_size              = 50
+    instance_types         = ["m6i.large", "m5.large", "m5n.large", "m5zn.large"]
+    vpc_security_group_ids = [aws_security_group.additional.id]
+  }
+
+
+  eks_managed_node_groups = {
+    example = {
+      desired_size = 2
+
+      instance_types = ["t3.large"]
+      tags           = local.tags
+    }
+  }
+
+  tags = local.tags
+}
+
+################################################################################
+# Supporting resources
+################################################################################
+
+module "vpc" {
+  source  = "terraform-aws-modules/vpc/aws"
+  version = "~> 3.0"
+
+  name = local.name
+  cidr = "10.0.0.0/16"
+
+  azs             = ["${local.region}a", "${local.region}b", "${local.region}c"]
+  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
+  public_subnets  = ["10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24"]
+
+  enable_nat_gateway   = true
+  single_nat_gateway   = true
+  enable_dns_hostnames = true
+
+  enable_flow_log                      = true
+  create_flow_log_cloudwatch_iam_role  = true
+  create_flow_log_cloudwatch_log_group = true
+
+  public_subnet_tags = {
+    "kubernetes.io/cluster/${local.name}" = "shared"
+    "kubernetes.io/role/elb"              = 1
+  }
+
+  private_subnet_tags = {
+    "kubernetes.io/cluster/${local.name}" = "shared"
+    "kubernetes.io/role/internal-elb"     = 1
+  }
+
+  tags = local.tags
+}
+
+resource "aws_security_group" "additional" {
+  name_prefix = "${local.name}-additional"
+  vpc_id      = module.vpc.vpc_id
+
+  ingress {
+    from_port = 22
+    to_port   = 22
+    protocol  = "tcp"
+    cidr_blocks = [
+      "10.0.0.0/8",
+      "172.16.0.0/12",
+      "192.168.0.0/16",
+    ]
+  }
+
+  # 443, 53, 123 is already allowed
+  egress {
+    from_port        = 80
+    to_port          = 80
+    protocol         = "tcp"
+    cidr_blocks      = ["0.0.0.0/0"]
+    ipv6_cidr_blocks = ["::/0"]
+  }
+
+
+  tags = local.tags
+}
+

+ 135 - 0
terraform/aws/modules/cluster/outputs.tf

@@ -0,0 +1,135 @@
+################################################################################
+# Cluster
+################################################################################
+
+output "cluster_arn" {
+  description = "The Amazon Resource Name (ARN) of the cluster"
+  value       = module.eks.cluster_arn
+}
+
+output "cluster_certificate_authority_data" {
+  description = "Base64 encoded certificate data required to communicate with the cluster"
+  value       = module.eks.cluster_certificate_authority_data
+}
+
+output "cluster_endpoint" {
+  description = "Endpoint for your Kubernetes API server"
+  value       = module.eks.cluster_endpoint
+}
+
+output "cluster_id" {
+  description = "The name/id of the EKS cluster. Will block on cluster creation until the cluster is really ready"
+  value       = module.eks.cluster_id
+}
+
+output "cluster_oidc_issuer_url" {
+  description = "The URL on the EKS cluster for the OpenID Connect identity provider"
+  value       = module.eks.cluster_oidc_issuer_url
+}
+
+output "cluster_platform_version" {
+  description = "Platform version for the cluster"
+  value       = module.eks.cluster_platform_version
+}
+
+output "cluster_status" {
+  description = "Status of the EKS cluster. One of `CREATING`, `ACTIVE`, `DELETING`, `FAILED`"
+  value       = module.eks.cluster_status
+}
+
+output "cluster_security_group_id" {
+  description = "Cluster security group that was created by Amazon EKS for the cluster. Managed node groups use this security group for control-plane-to-data-plane communication. Referred to as 'Cluster security group' in the EKS console"
+  value       = module.eks.cluster_security_group_id
+}
+
+################################################################################
+# Security Group
+################################################################################
+
+output "cluster_security_group_arn" {
+  description = "Amazon Resource Name (ARN) of the cluster security group"
+  value       = module.eks.cluster_security_group_arn
+}
+
+################################################################################
+# IRSA
+################################################################################
+
+output "oidc_provider_arn" {
+  description = "The ARN of the OIDC Provider if `enable_irsa = true`"
+  value       = module.eks.oidc_provider_arn
+}
+
+################################################################################
+# IAM Role
+################################################################################
+
+output "cluster_iam_role_name" {
+  description = "IAM role name of the EKS cluster"
+  value       = module.eks.cluster_iam_role_name
+}
+
+output "cluster_iam_role_arn" {
+  description = "IAM role ARN of the EKS cluster"
+  value       = module.eks.cluster_iam_role_arn
+}
+
+output "cluster_iam_role_unique_id" {
+  description = "Stable and unique string identifying the IAM role"
+  value       = module.eks.cluster_iam_role_unique_id
+}
+
+################################################################################
+# EKS Addons
+################################################################################
+
+output "cluster_addons" {
+  description = "Map of attribute maps for all EKS cluster addons enabled"
+  value       = module.eks.cluster_addons
+}
+
+################################################################################
+# EKS Identity Provider
+################################################################################
+
+output "cluster_identity_providers" {
+  description = "Map of attribute maps for all EKS identity providers enabled"
+  value       = module.eks.cluster_identity_providers
+}
+
+################################################################################
+# CloudWatch Log Group
+################################################################################
+
+output "cloudwatch_log_group_name" {
+  description = "Name of cloudwatch log group created"
+  value       = module.eks.cloudwatch_log_group_name
+}
+
+output "cloudwatch_log_group_arn" {
+  description = "Arn of cloudwatch log group created"
+  value       = module.eks.cloudwatch_log_group_arn
+}
+
+################################################################################
+# Fargate Profile
+################################################################################
+
+output "fargate_profiles" {
+  description = "Map of attribute maps for all EKS Fargate Profiles created"
+  value       = module.eks.fargate_profiles
+}
+
+################################################################################
+# Additional
+################################################################################
+
+output "aws_auth_configmap_yaml" {
+  description = "Formatted yaml output for base aws-auth configmap containing roles used in cluster node groups/fargate profiles"
+  value       = module.eks.aws_auth_configmap_yaml
+}
+
+output "eks_cluster_auth_token" {
+  value     = data.aws_eks_cluster_auth.this.token
+  sensitive = true
+}

+ 10 - 0
terraform/aws/modules/cluster/provider.tf

@@ -0,0 +1,10 @@
+terraform {
+  required_version = ">= 0.13"
+
+  required_providers {
+    aws = {
+      source  = "hashicorp/aws"
+      version = "~> 3.0"
+    }
+  }
+}

+ 16 - 0
terraform/aws/modules/cluster/variables.tf

@@ -0,0 +1,16 @@
+variable "cluster_name" {
+  type    = string
+  default = "eso-e2e-managed"
+}
+
+variable "irsa_sa_name" {
+  type = string
+}
+
+variable "irsa_sa_namespace" {
+  type = string
+}
+
+variable "cluster_region" {
+  type = string
+}

+ 11 - 0
terraform/aws/outputs.tf

@@ -0,0 +1,11 @@
+output "cluster_arn" {
+  value = module.cluster.cluster_arn
+}
+
+output "cluster_iam_role_arn" {
+  value = module.cluster.cluster_iam_role_arn
+}
+
+output "aws_auth_configmap_yaml" {
+  value = module.cluster.aws_auth_configmap_yaml
+}

+ 11 - 0
terraform/aws/provider.tf

@@ -0,0 +1,11 @@
+terraform {
+  required_version = ">= 0.13"
+
+   backend "s3" {
+     bucket = "eso-e2e-aws-tfstate"
+     key    = "aws-tfstate"
+     region = "eu-west-1"
+   }
+
+  required_providers {}
+}

+ 19 - 0
terraform/aws/variables.tf

@@ -0,0 +1,19 @@
+variable "AWS_SA_NAME" {
+  type    = string
+  default = "eso-e2e-test"
+}
+
+variable "AWS_SA_NAMESPACE" {
+  type    = string
+  default = "default"
+}
+
+variable "AWS_REGION" {
+  type    = string
+  default = "eu-west-1"
+}
+
+variable "AWS_CLUSTER_NAME" {
+  type    = string
+  default = "eso-e2e-managed"
+}

+ 20 - 0
terraform/gcp/eso_gcp_modules/gke/main.tf

@@ -1,4 +1,5 @@
 resource "google_service_account" "default" {
 resource "google_service_account" "default" {
+  project    = var.project_id
   account_id = var.GCP_GSA_NAME
   account_id = var.GCP_GSA_NAME
 }
 }
 
 
@@ -27,6 +28,7 @@ resource "google_service_account_iam_member" "pod_identity_e2e" {
 }
 }
 
 
 resource "google_container_cluster" "primary" {
 resource "google_container_cluster" "primary" {
+  project                  = var.project_id
   name                     = "${var.env}-cluster"
   name                     = "${var.env}-cluster"
   location                 = var.zone
   location                 = var.zone
   remove_default_node_pool = true
   remove_default_node_pool = true
@@ -43,6 +45,7 @@ resource "google_container_cluster" "primary" {
 }
 }
 
 
 resource "google_container_node_pool" "nodes" {
 resource "google_container_node_pool" "nodes" {
+  project    = var.project_id
   name       = "${google_container_cluster.primary.name}-node-pool"
   name       = "${google_container_cluster.primary.name}-node-pool"
   location   = google_container_cluster.primary.location
   location   = google_container_cluster.primary.location
   cluster    = google_container_cluster.primary.name
   cluster    = google_container_cluster.primary.name
@@ -57,3 +60,20 @@ resource "google_container_node_pool" "nodes" {
     ]
     ]
   }
   }
 }
 }
+
+provider "kubernetes" {
+  host                   = "https://${google_container_cluster.primary.endpoint}"
+  token                  = data.google_client_config.default.access_token
+  cluster_ca_certificate = base64decode(google_container_cluster.primary.master_auth.0.cluster_ca_certificate)
+}
+
+data "google_client_config" "default" {}
+
+resource "kubernetes_service_account" "test" {
+  metadata {
+    name = var.GCP_KSA_NAME
+    annotations = {
+      "iam.gke.io/gcp-service-account" : "${var.GCP_GSA_NAME}@${var.project_id}.iam.gserviceaccount.com"
+    }
+  }
+}

+ 2 - 0
terraform/gcp/eso_gcp_modules/network/main.tf

@@ -1,9 +1,11 @@
 resource "google_compute_network" "env-vpc" {
 resource "google_compute_network" "env-vpc" {
+  project = var.project_id
   name          =  "${var.env}-vpc"
   name          =  "${var.env}-vpc"
   auto_create_subnetworks = false
   auto_create_subnetworks = false
 }
 }
 
 
 resource "google_compute_subnetwork" "env-subnet" {
 resource "google_compute_subnetwork" "env-subnet" {
+  project = var.project_id
   name          = "${google_compute_network.env-vpc.name}-subnet"
   name          = "${google_compute_network.env-vpc.name}-subnet"
   region        = var.region
   region        = var.region
   network       = google_compute_network.env-vpc.name
   network       = google_compute_network.env-vpc.name

+ 3 - 0
terraform/gcp/eso_gcp_modules/network/variable.tf

@@ -13,3 +13,6 @@ variable "ip_service_range" {
 variable "region" {
 variable "region" {
   default = "europe-west1"
   default = "europe-west1"
 }
 }
+variable "project_id" {
+  type = string
+}

+ 1 - 0
terraform/gcp/main.tf

@@ -11,6 +11,7 @@ module "test-network" {
   env = var.env
   env = var.env
   region = var.region
   region = var.region
   ip_cidr_range = var.ip_cidr_range
   ip_cidr_range = var.ip_cidr_range
+  project_id = var.project_id
 }
 }
 
 
 module "test-cluster" {
 module "test-cluster" {

+ 1 - 1
tools.go

@@ -5,6 +5,6 @@ package tools
 
 
 import (
 import (
 	_ "github.com/ahmetb/gen-crd-api-reference-docs"
 	_ "github.com/ahmetb/gen-crd-api-reference-docs"
-	_ "github.com/onsi/ginkgo/ginkgo"
+	_ "github.com/onsi/ginkgo/v2/ginkgo"
 	_ "sigs.k8s.io/controller-tools/cmd/controller-gen"
 	_ "sigs.k8s.io/controller-tools/cmd/controller-gen"
 )
 )