Browse Source

fixing conflicts and pulling changes

Kian 4 years ago
parent
commit
db6b9297cd

+ 4 - 9
.github/workflows/ci.yml

@@ -230,13 +230,6 @@ jobs:
           key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}
           restore-keys: ${{ runner.os }}-pkg-
 
-      - name: Build Artifacts
-        env:
-          # We're using docker buildx, which doesn't actually load the images it
-          # builds by default. Specifying --load does so.
-          BUILD_ARGS: "--load"
-        run: make docker.build
-
       - name: Login to Docker
         uses: docker/login-action@v1
         if: env.GHCR_USERNAME != ''
@@ -245,9 +238,11 @@ jobs:
           username: ${{ secrets.GHCR_USERNAME }}
           password: ${{ secrets.GHCR_TOKEN }}
 
-      - name: Publish Artifacts
+      - name: Build & Publish Artifacts
         if: env.GHCR_USERNAME != ''
-        run: make docker.push
+        env:
+          BUILD_ARGS: "--push --platform linux/amd64,linux/arm64"
+        run: make docker.build
 
       - name: Promote Artifacts to main release channel
         if: github.ref == 'refs/heads/main' && env.GHCR_USERNAME != ''

+ 16 - 0
.github/workflows/e2e.yml

@@ -71,7 +71,15 @@ jobs:
         node_image: kindest/node:v1.20.7
         name: external-secrets
 
+    - name: Setup Docker Buildx
+      uses: docker/setup-buildx-action@v1
+      with:
+        version: ${{ env.DOCKER_BUILDX_VERSION }}
+        install: true
+
     - name: Run e2e Tests
+      env:
+        BUILD_ARGS: "--load"
       run: |
         export PATH=$PATH:$(go env GOPATH)/bin
         go get github.com/onsi/ginkgo/ginkgo
@@ -128,7 +136,15 @@ jobs:
         node_image: kindest/node:v1.20.7
         name: external-secrets
 
+    - name: Setup Docker Buildx
+      uses: docker/setup-buildx-action@v1
+      with:
+        version: ${{ env.DOCKER_BUILDX_VERSION }}
+        install: true
+
     - name: Run e2e Tests
+      env:
+        BUILD_ARGS: "--load"
       run: |
         export PATH=$PATH:$(go env GOPATH)/bin
         go get github.com/onsi/ginkgo/ginkgo

+ 1 - 0
.github/workflows/release.yml

@@ -76,3 +76,4 @@ jobs:
         run: make docker.promote
         env:
           RELEASE_TAG: ${{ github.event.inputs.version }}
+          SOURCE_TAG: main

+ 1 - 1
.gitignore

@@ -12,7 +12,7 @@ cover.out
 # helm chart dependencies
 **/charts/*.tgz
 **/charts/**/requirements.lock
-
+.tagmanifest
 deploy/charts/external-secrets/templates/crds/*.yaml
 
 site/

+ 3 - 2
Dockerfile

@@ -1,6 +1,7 @@
 FROM alpine:3.14.0
-
-COPY bin/external-secrets /bin/external-secrets
+ARG TARGETOS
+ARG TARGETARCH
+COPY bin/external-secrets-${TARGETOS}-${TARGETARCH} /bin/external-secrets
 
 # Run as UID for nobody
 USER 65534

+ 24 - 13
Makefile

@@ -5,10 +5,13 @@ SHELL         := /bin/bash
 MAKEFLAGS     += --warn-undefined-variables
 .SHELLFLAGS   := -euo pipefail -c
 
+ARCH = amd64 arm64
+BUILD_ARGS ?=
+
 # default target is build
 .DEFAULT_GOAL := all
 .PHONY: all
-all: build
+all: $(addprefix build-,$(ARCH))
 
 # Image registry for build/push image targets
 IMAGE_REGISTRY ?= ghcr.io/external-secrets/external-secrets
@@ -34,7 +37,7 @@ ifeq ($(shell git tag),)
 VERSION := $(shell echo "v0.0.0-$$(git rev-list HEAD --count)-g$$(git describe --dirty --always)" | sed 's/-/./2' | sed 's/-/./2')
 else
 # use tags
-VERSION := $(shell git describe --dirty --always --tags | sed 's/-/./2' | sed 's/-/./2')
+VERSION := $(shell git describe --dirty --always --tags --exclude 'helm*' | sed 's/-/./2' | sed 's/-/./2')
 endif
 
 # ====================================================================================
@@ -88,15 +91,19 @@ test.e2e: generate ## Run e2e tests
 	@$(OK) go test unit-tests
 
 .PHONY: build
-build: generate ## Build binary
-	@$(INFO) go build
-	@CGO_ENABLED=0 go build -o $(OUTPUT_DIR)/external-secrets main.go
-	@$(OK) go build
+build: $(addprefix build-,$(ARCH))
+
+.PHONY: build-%
+build-%: generate ## Build binary for the specified arch
+	@$(INFO) go build $*
+	@CGO_ENABLED=0 GOOS=linux GOARCH=$* \
+		go build -o '$(OUTPUT_DIR)/external-secrets-linux-$*' main.go
+	@$(OK) go build $*
 
 # Check install of golanci-lint
 lint.check:
 	@if ! golangci-lint --version > /dev/null 2>&1; then \
-		echo -e "\033[0;33mgolangci-lint is not installed: run \`\033[0;32mmake lint-install\033[0m\033[0;33m\` or install it from https://golangci-lint.run\033[0m"; \
+		echo -e "\033[0;33mgolangci-lint is not installed: run \`\033[0;32mmake lint.install\033[0m\033[0;33m\` or install it from https://golangci-lint.run\033[0m"; \
 		exit 1; \
 	fi
 
@@ -194,7 +201,7 @@ serve-docs:
 
 build.all: docker.build helm.build
 
-docker.build: build ## Build the docker image
+docker.build: $(addprefix build-,$(ARCH)) ## Build the docker image
 	@$(INFO) docker build
 	@docker build . $(BUILD_ARGS) -t $(IMAGE_REGISTRY):$(VERSION)
 	@$(OK) docker build
@@ -210,11 +217,15 @@ RELEASE_TAG ?= main
 SOURCE_TAG ?= $(VERSION)
 
 docker.promote:
-	@$(INFO) docker pull $(SOURCE_TAG)
-	@docker pull $(IMAGE_REGISTRY):$(SOURCE_TAG)
-	@docker tag $(IMAGE_REGISTRY):$(SOURCE_TAG) $(IMAGE_REGISTRY):$(RELEASE_TAG)
-	@docker push $(IMAGE_REGISTRY):$(RELEASE_TAG)
-	@$(OK) docker push $(RELEASE_TAG)
+	@$(INFO) promoting $(SOURCE_TAG) to $(RELEASE_TAG)
+	docker manifest inspect $(IMAGE_REGISTRY):$(SOURCE_TAG) > .tagmanifest
+	for digest in $$(jq -r '.manifests[].digest' < .tagmanifest); do \
+		docker pull $(IMAGE_REGISTRY)@$$digest; \
+	done
+	docker manifest create $(IMAGE_REGISTRY):$(RELEASE_TAG) \
+		$$(jq -j '"--amend $(IMAGE_REGISTRY)@" + .manifests[].digest + " "' < .tagmanifest)
+	docker manifest push $(IMAGE_REGISTRY):$(RELEASE_TAG)
+	@$(OK) docker push $(RELEASE_TAG) \
 
 # ====================================================================================
 # Help

+ 2 - 2
deploy/charts/external-secrets/Chart.yaml

@@ -2,8 +2,8 @@ apiVersion: v2
 name: external-secrets
 description: External secret management for Kubernetes
 type: application
-version: "0.2.3"
-appVersion: "v0.2.3"
+version: "0.3.2"
+appVersion: "v0.3.2"
 kubeVersion: ">= 1.11.0-0"
 keywords:
   - kubernetes-external-secrets

+ 1 - 1
deploy/charts/external-secrets/README.md

@@ -4,7 +4,7 @@
 
 [//]: # (README.md generated by gotmpl. DO NOT EDIT.)
 
-![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![Version: 0.2.3](https://img.shields.io/badge/Version-0.2.3-informational?style=flat-square)
+![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![Version: 0.3.2](https://img.shields.io/badge/Version-0.3.2-informational?style=flat-square)
 
 External secret management for Kubernetes
 

+ 2 - 0
deploy/charts/external-secrets/templates/rbac.yaml

@@ -21,6 +21,7 @@ rules:
     resources:
     - "externalsecrets"
     - "externalsecrets/status"
+    - "externalsecrets/finalizers"
     verbs:
     - "update"
     - "patch"
@@ -51,6 +52,7 @@ rules:
     - "create"
     - "update"
     - "delete"
+    - "patch"
   - apiGroups:
     - ""
     resources:

+ 16 - 15
docs/snippets/azkv-secret-store.yaml

@@ -3,18 +3,19 @@ kind: SecretStore
 metadata:
   name: example-secret-store
 spec:
-  # provider type: azure keyvault
-  azurekv:
-    # azure tenant ID, see: https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/active-directory-how-to-find-tenant
-    tenantId: "d3bc2180-xxxx-xxxx-xxxx-154105743342"
-    # URL of your vault instance, see: https://docs.microsoft.com/en-us/azure/key-vault/general/about-keys-secrets-certificates
-    vaultUrl: "https://my-keyvault-name.vault.azure.net"
-    authSecretRef:
-      # points to the secret that contains
-      # the azure service principal credentials
-      clientId:
-        name: azure-secret-sp
-        key: ClientID
-      clientSecret:
-        name: azure-secret-sp
-        key: ClientSecret
+  provider:
+    # provider type: azure keyvault
+    azurekv:
+      # azure tenant ID, see: https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/active-directory-how-to-find-tenant
+      tenantId: "d3bc2180-xxxx-xxxx-xxxx-154105743342"
+      # URL of your vault instance, see: https://docs.microsoft.com/en-us/azure/key-vault/general/about-keys-secrets-certificates
+      vaultUrl: "https://my-keyvault-name.vault.azure.net"
+      authSecretRef:
+        # points to the secret that contains
+        # the azure service principal credentials
+        clientId:
+          name: azure-secret-sp
+          key: ClientID
+        clientSecret:
+          name: azure-secret-sp
+          key: ClientSecret

+ 3 - 2
e2e/Makefile

@@ -5,6 +5,7 @@ SHELL       := /bin/bash
 IMG_TAG     = test
 IMG         = local/external-secrets-e2e:$(IMG_TAG)
 K8S_VERSION = "1.20.7"
+BUILD_ARGS  ?=
 export FOCUS := $(FOCUS)
 
 start-kind: ## Start kind cluster
@@ -18,7 +19,7 @@ test: e2e-image ## Run e2e tests against current kube context
 	$(MAKE) -C ../ docker.build \
 		IMAGE_REGISTRY=local/external-secrets \
 		VERSION=$(IMG_TAG) \
-		BUILD_ARGS="--build-arg ARCHS=amd64"
+		ARCH=amd64
 	kind load docker-image --name="external-secrets" local/external-secrets:$(IMG_TAG)
 	kind load docker-image --name="external-secrets" $(IMG)
 	./run.sh
@@ -31,7 +32,7 @@ e2e-image: e2e-bin
 	mkdir -p k8s
 	$(MAKE) -C ../ helm.generate
 	cp -r ../deploy ./k8s
-	docker build -t $(IMG) .
+	docker build $(BUILD_ARGS) -t $(IMG) .
 
 stop-kind: ## Stop kind cluster
 	kind delete cluster \

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

@@ -35,9 +35,7 @@ var _ = Describe("[azure] ", func() {
 	DescribeTable("sync secrets", framework.TableFunc(f, prov),
 		Entry(common.SimpleDataSync(f)),
 		Entry(common.NestedJSONWithGJSON(f)),
-		// TODO: dataFrom is not working as expected RN
-		// see: https://github.com/external-secrets/external-secrets/issues/263
-		// Entry(common.JSONDataFromSync(f)),
+		Entry(common.JSONDataFromSync(f)),
 		Entry(common.JSONDataWithProperty(f)),
 		Entry(common.JSONDataWithTemplate(f)),
 		Entry(common.DockerJSONConfig(f)),

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

@@ -13,13 +13,21 @@ limitations under the License.
 package gcp
 
 import (
+	"crypto/rand"
+	"crypto/x509"
+	"encoding/pem"
+	"fmt"
 	"os"
 
 	// nolint
 	. "github.com/onsi/ginkgo"
 	// nolint
 	. "github.com/onsi/ginkgo/extensions/table"
+	v1 "k8s.io/api/core/v1"
+	p12 "software.sslmate.com/src/go-pkcs12"
 
+	// nolint
+	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"
 )
@@ -30,6 +38,108 @@ var _ = Describe("[gcp] ", func() {
 	projectID := os.Getenv("GCP_PROJECT_ID")
 	prov := newgcpProvider(f, credentials, projectID)
 
+	// 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-----
+MIIFQjCCBCqgAwIBAgISBHszg5W2maz/7CIxGrf7mqukMA0GCSqGSIb3DQEBCwUA
+MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
+EwJSMzAeFw0yMTA3MjQxMjQyMzNaFw0yMTEwMjIxMjQyMzFaMCgxJjAkBgNVBAMT
+HXRlbXBvcmFyeS5leHRlcm5hbC1zZWNyZXRzLmlvMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAyRROdZskA8qnGnoMgQ5Ry5MVY/lgo3HzlhKq02u23J2w
+14w+LiEU2hcSJKYv5OXysbfq7M52u2zXYZXs6krkQZlYNpFw7peZ0JtUbVkSpST/
+X4b1GJKDSkRs7fTi+v+pb9OT9rTbtd8jfGe/YCe5rjXEm/ih2DgS13737lKCD5n6
+3QUOG7CR+SKFeRXOGkncqJHAyRkpNfAmS8m1C+ucodfjSFoqAwwVGx7eyEktG4s/
+JbwLEb03hGrP15vnnOgxQmiAzWskxhMyHX6vmA71Oq4F3RVsuD3CEjKzgJ2+ghk3
+BIY3DZSfSReWSMYM573YFglENi+qJK012XnFmZcevwIDAQABo4ICWjCCAlYwDgYD
+VR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNV
+HRMBAf8EAjAAMB0GA1UdDgQWBBRvn1wGi46XcyhRIIxJkSSUoCyoNzAfBgNVHSME
+GDAWgBQULrMXt1hWy65QCUDmH6+dixTCxjBVBggrBgEFBQcBAQRJMEcwIQYIKwYB
+BQUHMAGGFWh0dHA6Ly9yMy5vLmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDov
+L3IzLmkubGVuY3Iub3JnLzAoBgNVHREEITAfgh10ZW1wb3JhcnkuZXh0ZXJuYWwt
+c2VjcmV0cy5pbzBMBgNVHSAERTBDMAgGBmeBDAECATA3BgsrBgEEAYLfEwEBATAo
+MCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCCAQYGCisG
+AQQB1nkCBAIEgfcEgfQA8gB3APZclC/RdzAiFFQYCDCUVo7jTRMZM7/fDC8gC8xO
+8WTjAAABetjA0asAAAQDAEgwRgIhAPYbBNim7q3P0qmD9IrAx1E1fEClYpoLrAVs
+4LGBkQobAiEA+IaTPWs9eHmqtCwar96PNxE0Iucak0DYkgfcWJT5gfYAdwBvU3as
+MfAxGdiZAKRRFf93FRwR2QLBACkGjbIImjfZEwAAAXrYwNJTAAAEAwBIMEYCIQDY
+xWJKFljK1AW2z/uVsU7TwcAAcIqUf5/nhS04JAwpfwIhANDTvwvcRvPebU7fv6dq
+lNH1g2Oyv/4Vm7W+Vrc5cFD0MA0GCSqGSIb3DQEBCwUAA4IBAQAR29s3pDGZbNPN
+5K+Zqg9UDT8s+P0fb9r97T7hWEFkiUtG4bz7QvGzSoDXhD/DZkdjLmkX7+bLiE3L
+hRSSYe+Am+Bw5soyzefX2FHAUeOLeK0mJhOrdiKqrW4nnvOOJWLkcWS799kW2z7j
+2MgUWTOz/xXGUOWHt1KjyoM31G3shoAIB9lg3lHbuVIyDd3yyUpjt0zevVdYrO9G
+CgI2mJfv26EiddBvgudzN+R5Ayis9czaFHu8gpplaf9DahaKs1Uys6lg0HnzRn3l
+XMYitHfpGhc+DTTiTWMQ13J0b1j4yv8A7ZaG2366aa28oSTD6eQFhmVCBwa54j++
+IOwzHn5R
+-----END CERTIFICATE-----
+`
+		privkeyPEM := `-----BEGIN PRIVATE KEY-----
+MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDJFE51myQDyqca
+egyBDlHLkxVj+WCjcfOWEqrTa7bcnbDXjD4uIRTaFxIkpi/k5fKxt+rszna7bNdh
+lezqSuRBmVg2kXDul5nQm1RtWRKlJP9fhvUYkoNKRGzt9OL6/6lv05P2tNu13yN8
+Z79gJ7muNcSb+KHYOBLXfvfuUoIPmfrdBQ4bsJH5IoV5Fc4aSdyokcDJGSk18CZL
+ybUL65yh1+NIWioDDBUbHt7ISS0biz8lvAsRvTeEas/Xm+ec6DFCaIDNayTGEzId
+fq+YDvU6rgXdFWy4PcISMrOAnb6CGTcEhjcNlJ9JF5ZIxgznvdgWCUQ2L6okrTXZ
+ecWZlx6/AgMBAAECggEBAI9sDX5zFuAhdsk6zppqtUrn8TTq1dQe3ihnzjKYvMhl
+LZLA9EUA0ZexJv6/DqBMp6u9TDJ2HVgYDRQM1PxUSLTFhJb/bDayKUMS18ha5SKn
+3gKsBzvsnPqnDa84oYF4Q8mAdyRb4e66ZtxAP8985kLtFPxO/llzvXS5mmwBq8Ul
+wlLOg5xAXubm3vgLyFm2GW9qI6ZvY9mmh1mv5ZLP8/8hikRjwJijnX3dyqqIAYnc
+DHjJYy2I1VxGJybqVQRquG++Tl4qLXbOUZ/lhKe62ARx/MBR9lEst5TURc9N7U3D
+Mgsu7FcFwqjVkig3P0XiNRWwCu0HrYee5rLXmtDnF9kCgYEA69+OuJM/RIsrLQQd
+1alppgT+SFyaJM3X1MJD3yxW6Vqqvkhqe7+XCWnmVYcpHPcilWmZnnQ3PiWqPJ8A
+3mIMp+Xg0ddFQXb3n7z4D0Mg4IPzvSKnlieTT1rDhhHRv/xArw1UBkF6kqcnZizZ
+FcWcOIt/dYodTWZzPJtLtf7QW0sCgYEA2jy0vJ5rg0/CSinkccreegC6gbbd+oE9
+uR/aGeu1XmnULoYYMMy7BLqd8/OiXvujbgUSUWnzbEclR88dPDkiRxDL7mYiaCn+
+l9jPuVB1W5x6irJdG/7lpSnLuijpkzey177ZKrlfGsOjtVZsc1ytnqTCWsF1r9eY
+yXCSvkJQjd0CgYEA5+vl0hh+MfBA4L9WcnpkNehc+luK+LspB7qHr81SG5qZngVo
+JgspAAmPf/Mo+qEI8S5m7MVKeCHitD6HRSHVXdUK7GklYIwQSJEuuxr/HaLAquyD
+KYH6NyGAdLfarFHka/rH7mq9kasnczCPtveZdoO7LKBD1ZHxptrvY6CLz+cCgYEA
+yEq2xfXPTrDA7DgOhbFfBjHs+mfOyr4a2/Czxt5hkskmB5ziTsdXTTvJA8Ay4WGp
+2Kum6DmJQ3L4cDNR7ZeyMe7ke2QZZ+hC1TITU0zYqL+wZ+LTOYJzWWZGqBAsbwTL
+it6JiYCgHHw5n5A18Jq6bcNg7NJpJH2GqDo9M4jBTbECgYEAlMuvNExEXGVzWrGF
+NXHpAev64RJ2jTq59jtmxWrNvzeWJREOWd/Nt+0t+bE0sHMfgaMrhNFWiR8oesrF
+Jdx0ECYawviQoreDAyIXV6HouoeRbDtLZ9AJvxMoIjGcjAR2FQHc3yx4h/lf3Tfx
+x6HaRh+EUwU51von6M9lEF9/p5Q=
+-----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, "")
+
+		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.ExternalSecret.Spec.Data = []esv1alpha1.ExternalSecretData{
+			{
+				SecretKey: "mysecret",
+				RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
+					Key: cloudSecretName,
+				},
+			},
+		}
+
+		tc.ExternalSecret.Spec.Target.Template = &esv1alpha1.ExternalSecretTemplate{
+			Type: v1.SecretTypeTLS,
+			Data: map[string]string{
+				"tls.crt": "{{ .mysecret | pkcs12cert | pemCertificate }}",
+				"tls.key": "{{ .mysecret | pkcs12key | pemPrivateKey }}",
+			},
+		}
+	}
+
 	DescribeTable("sync secrets", framework.TableFunc(f, prov),
 		Entry(common.SimpleDataSync(f)),
 		Entry(common.JSONDataWithProperty(f)),
@@ -40,5 +150,6 @@ var _ = Describe("[gcp] ", func() {
 		Entry(common.DataPropertyDockerconfigJSON(f)),
 		Entry(common.SSHKeySync(f)),
 		Entry(common.SSHKeySyncDataProperty(f)),
+		Entry("should sync p12 encoded cert secret", p12Cert),
 	)
 })

+ 1 - 0
go.mod

@@ -78,4 +78,5 @@ require (
 	k8s.io/utils v0.0.0-20210527160623-6fdb442a123b
 	sigs.k8s.io/controller-runtime v0.9.2
 	sigs.k8s.io/controller-tools v0.5.0
+	software.sslmate.com/src/go-pkcs12 v0.0.0-20210415151418-c5206de65a78
 )

+ 2 - 0
go.sum

@@ -1111,3 +1111,5 @@ sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
 sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
 sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
+software.sslmate.com/src/go-pkcs12 v0.0.0-20210415151418-c5206de65a78 h1:SqYE5+A2qvRhErbsXFfUEUmpWEKxxRSMgGLkvRAFOV4=
+software.sslmate.com/src/go-pkcs12 v0.0.0-20210415151418-c5206de65a78/go.mod h1:B7Wf0Ya4DHF9Yw+qfZuJijQYkWicqDa+79Ytmmq3Kjg=

+ 8 - 6
pkg/controllers/externalsecret/externalsecret_controller.go

@@ -54,6 +54,7 @@ const (
 	errStoreRef              = "could not get store reference"
 	errStoreProvider         = "could not get store provider"
 	errStoreClient           = "could not get provider client"
+	errCloseStoreClient      = "could not close provider client"
 	errSetCtrlReference      = "could not set ExternalSecret controller reference: %w"
 	errFetchTplFrom          = "error fetching templateFrom data: %w"
 	errGetSecretData         = "could not get secret data from provider: %w"
@@ -63,7 +64,6 @@ const (
 	errPolicyMergeMutate     = "unable to mutate secret %s: %w"
 	errPolicyMergePatch      = "unable to patch secret %s: %w"
 	errGetSecretKey          = "key %q from ExternalSecret %q: %w"
-	errClientClose           = "error closing the connection: %w"
 	errTplCMMissingKey       = "error in configmap %s: missing key %s"
 	errTplSecMissingKey      = "error in secret %s: missing key %s"
 )
@@ -138,6 +138,13 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
 		return ctrl.Result{RequeueAfter: requeueAfter}, nil
 	}
 
+	defer func() {
+		err = secretClient.Close()
+		if err != nil {
+			log.Error(err, errCloseStoreClient)
+		}
+	}()
+
 	refreshInt := time.Hour
 	if externalSecret.Spec.RefreshInterval != nil {
 		refreshInt = externalSecret.Spec.RefreshInterval.Duration
@@ -376,11 +383,6 @@ func (r *Reconciler) getProviderSecretData(ctx context.Context, providerClient p
 		providerData[secretRef.SecretKey] = secretData
 	}
 
-	err := providerClient.Close()
-	if err != nil {
-		return nil, fmt.Errorf(errClientClose, err)
-	}
-
 	return providerData, nil
 }
 

+ 45 - 38
pkg/provider/azure/keyvault/keyvault.go

@@ -18,7 +18,6 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
-	"path"
 	"strings"
 
 	"github.com/Azure/azure-sdk-for-go/profiles/latest/keyvault/keyvault"
@@ -34,6 +33,10 @@ import (
 	"github.com/external-secrets/external-secrets/pkg/provider/schema"
 )
 
+const (
+	defaultObjType = "secret"
+)
+
 // Provider satisfies the provider interface.
 type Provider struct{}
 
@@ -87,24 +90,15 @@ func newClient(ctx context.Context, store esv1alpha1.GenericStore, kube client.C
 // The Object Type is defined as a prefix in the ref.Name , if no prefix is defined , we assume a secret is required.
 func (a *Azure) GetSecret(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
 	version := ""
-	objectType := "secret"
 	basicClient := a.baseClient
+	objectType, secretName := getObjType(ref)
 
 	if ref.Version != "" {
 		version = ref.Version
 	}
 
-	secretName := ref.Key
-	nameSplitted := strings.Split(secretName, "/")
-
-	if len(nameSplitted) > 1 {
-		objectType = nameSplitted[0]
-		secretName = nameSplitted[1]
-		// TODO: later tokens can be used to read the secret tags
-	}
-
 	switch objectType {
-	case "secret":
+	case defaultObjType:
 		// returns a SecretBundle with the secret value
 		// https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/services/keyvault/v7.0/keyvault#SecretBundle
 		secretResp, err := basicClient.GetSecret(context.Background(), a.vaultURL, secretName, version)
@@ -142,37 +136,36 @@ func (a *Azure) GetSecret(ctx context.Context, ref esv1alpha1.ExternalSecretData
 }
 
 // Implements store.Client.GetSecretMap Interface.
-// retrieve ALL secrets in a specific keyvault.
-// ExternalSecretDataRemoteRef Key is mandatory, but with current model we do not use its content.
-func (a *Azure) GetSecretMap(ctx context.Context, _ esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
-	basicClient := a.baseClient
-	secretsMap := make(map[string][]byte)
+// New version of GetSecretMap.
+func (a *Azure) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
+	objectType, secretName := getObjType(ref)
 
-	secretListIter, err := basicClient.GetSecretsComplete(context.Background(), a.vaultURL, nil)
-	if err != nil {
-		return nil, err
-	}
-	for secretListIter.NotDone() {
-		secretList := secretListIter.Response().Value
-		for _, secret := range *secretList {
-			if !*secret.Attributes.Enabled {
-				continue
-			}
-			secretName := path.Base(*secret.ID)
-			secretResp, err := basicClient.GetSecret(context.Background(), a.vaultURL, secretName, "")
-			secretValue := *secretResp.Value
-
-			if err != nil {
-				return nil, err
-			}
-			secretsMap[secretName] = []byte(secretValue)
-		}
-		err = secretListIter.Next()
+	switch objectType {
+	case defaultObjType:
+		data, err := a.GetSecret(ctx, ref)
 		if err != nil {
 			return nil, err
 		}
+
+		kv := make(map[string]string)
+		err = json.Unmarshal(data, &kv)
+		if err != nil {
+			return nil, fmt.Errorf("error unmarshalling json data: %w", err)
+		}
+
+		secretData := make(map[string][]byte)
+		for k, v := range kv {
+			secretData[k] = []byte(v)
+		}
+
+		return secretData, nil
+	case "cert":
+		return nil, fmt.Errorf("cannot get use dataFrom to get certificate secret")
+	case "key":
+		return nil, fmt.Errorf("cannot get use dataFrom to get key secret")
 	}
-	return secretsMap, nil
+
+	return nil, fmt.Errorf("unknown Azure Keyvault object Type for %s", secretName)
 }
 
 func (a *Azure) newAzureClient(ctx context.Context) (*keyvault.BaseClient, string, error) {
@@ -237,3 +230,17 @@ func (a *Azure) secretKeyRef(ctx context.Context, namespace string, secretRef sm
 func (a *Azure) Close() error {
 	return nil
 }
+
+func getObjType(ref esv1alpha1.ExternalSecretDataRemoteRef) (string, string) {
+	objectType := defaultObjType
+
+	secretName := ref.Key
+	nameSplitted := strings.Split(secretName, "/")
+
+	if len(nameSplitted) > 1 {
+		objectType = nameSplitted[0]
+		secretName = nameSplitted[1]
+		// TODO: later tokens can be used to read the secret tags
+	}
+	return objectType, secretName
+}

+ 5 - 16
pkg/provider/azure/keyvault/keyvault_test.go

@@ -157,26 +157,15 @@ func TestGetSecretWithoutVersion(t *testing.T) {
 func TestGetSecretMap(t *testing.T) {
 	testAzure, azureMock := newAzure()
 	ctx := context.Background()
-	rf := esv1alpha1.ExternalSecretDataRemoteRef{}
-	azureMock.AddSecret(testAzure.vaultURL, "testName", "My Secret", true)
-	azureMock.ExpectsGetSecretsComplete(ctx, testAzure.vaultURL, nil)
+	rf := esv1alpha1.ExternalSecretDataRemoteRef{
+		Key: "testName",
+	}
+	azureMock.AddSecret(testAzure.vaultURL, "testName", "{\"username\": \"user1\", \"pass\": \"123\"}", true)
 	azureMock.ExpectsGetSecret(ctx, testAzure.vaultURL, "testName", "")
 	secretMap, err := testAzure.GetSecretMap(ctx, rf)
 	azureMock.AssertExpectations(t)
 	tassert.Nil(t, err, "the return err should be nil")
-	tassert.Equal(t, secretMap, map[string][]byte{"testName": []byte("My Secret")})
-}
-
-func TestGetSecretMapNotEnabled(t *testing.T) {
-	testAzure, azureMock := newAzure()
-	ctx := context.Background()
-	rf := esv1alpha1.ExternalSecretDataRemoteRef{}
-	azureMock.AddSecret(testAzure.vaultURL, "testName", "My Secret", false)
-	azureMock.ExpectsGetSecretsComplete(ctx, testAzure.vaultURL, nil)
-	secretMap, err := testAzure.GetSecretMap(ctx, rf)
-	azureMock.AssertExpectations(t)
-	tassert.Nil(t, err, "the return err should be nil")
-	tassert.Empty(t, secretMap)
+	tassert.Equal(t, secretMap, map[string][]byte{"username": []byte("user1"), "pass": []byte("123")})
 }
 
 func newKVJWK(b []byte) *keyvault.JSONWebKey {

+ 14 - 6
pkg/provider/vault/vault.go

@@ -60,6 +60,7 @@ const (
 
 	errGetKubeSA        = "cannot get Kubernetes service account %q: %w"
 	errGetKubeSASecrets = "cannot find secrets bound to service account: %q"
+	errGetKubeSANoToken = "cannot find token in secrets bound to service account: %q"
 
 	errGetKubeSecret = "cannot get Kubernetes secret %q: %w"
 	errSecretKeyFmt  = "cannot find secret data for key: %q"
@@ -311,13 +312,20 @@ func (v *client) secretKeyRefForServiceAccount(ctx context.Context, serviceAccou
 	if len(serviceAccount.Secrets) == 0 {
 		return "", fmt.Errorf(errGetKubeSASecrets, ref.Name)
 	}
-	tokenRef := serviceAccount.Secrets[0]
+	for _, tokenRef := range serviceAccount.Secrets {
+		retval, err := v.secretKeyRef(ctx, &esmeta.SecretKeySelector{
+			Name:      tokenRef.Name,
+			Namespace: &ref.Namespace,
+			Key:       "token",
+		})
 
-	return v.secretKeyRef(ctx, &esmeta.SecretKeySelector{
-		Name:      tokenRef.Name,
-		Namespace: &ref.Namespace,
-		Key:       "token",
-	})
+		if err != nil {
+			continue
+		}
+
+		return retval, nil
+	}
+	return "", fmt.Errorf(errGetKubeSANoToken, ref.Name)
 }
 
 func (v *client) secretKeyRef(ctx context.Context, secretRef *esmeta.SecretKeySelector) (string, error) {