William Young 3 лет назад
Родитель
Сommit
b2b09fa06f
49 измененных файлов с 754 добавлено и 200 удалено
  1. 2 36
      Makefile
  2. 15 2
      apis/externalsecrets/v1beta1/secretstore_ibm_types.go
  3. 28 0
      apis/externalsecrets/v1beta1/secretstore_types.go
  4. 0 25
      apis/externalsecrets/v1beta1/secretstore_vault_types.go
  5. 16 0
      apis/externalsecrets/v1beta1/zz_generated.deepcopy.go
  6. 32 18
      cmd/root.go
  7. 2 1
      config/crds/bases/external-secrets.io_clusterexternalsecrets.yaml
  8. 26 8
      config/crds/bases/external-secrets.io_clustersecretstores.yaml
  9. 1 1
      config/crds/bases/external-secrets.io_externalsecrets.yaml
  10. 1 1
      config/crds/bases/external-secrets.io_pushsecrets.yaml
  11. 26 8
      config/crds/bases/external-secrets.io_secretstores.yaml
  12. 8 0
      config/crds/bases/kustomization.yaml
  13. 10 0
      deploy/charts/external-secrets/README.md
  14. 0 1
      deploy/charts/external-secrets/README.md.gotmpl
  15. 13 2
      deploy/charts/external-secrets/templates/cert-controller-service.yaml
  16. 4 0
      deploy/charts/external-secrets/templates/deployment.yaml
  17. 13 2
      deploy/charts/external-secrets/templates/service.yaml
  18. 14 4
      deploy/charts/external-secrets/templates/webhook-service.yaml
  19. 37 0
      deploy/charts/external-secrets/values.yaml
  20. 46 17
      deploy/crds/bundle.yaml
  21. 2 0
      docs/guides-metrics.md
  22. BIN
      docs/pictures/screenshot_container_auth_create_1.png
  23. BIN
      docs/pictures/screenshot_container_auth_create_2.png
  24. BIN
      docs/pictures/screenshot_container_auth_create_3.png
  25. BIN
      docs/pictures/screenshot_container_auth_create_button.png
  26. BIN
      docs/pictures/screenshot_container_auth_create_group.png
  27. BIN
      docs/pictures/screenshot_container_auth_create_group_1.png
  28. BIN
      docs/pictures/screenshot_container_auth_create_group_2.png
  29. BIN
      docs/pictures/screenshot_container_auth_create_group_3.png
  30. BIN
      docs/pictures/screenshot_container_auth_create_group_4.png
  31. BIN
      docs/pictures/screenshot_container_auth_iam_left.png
  32. 1 1
      docs/provider-1password-automation.md
  33. 21 7
      docs/provider-azure-key-vault.md
  34. 66 7
      docs/provider-ibm-secrets-manager.md
  35. 24 0
      docs/snippets/azkv-pkcs12-cert-external-secret.yaml
  36. 22 0
      docs/snippets/ibm-container-auth-volume.yaml
  37. 4 0
      docs/snippets/ibm-secret-store.yaml
  38. 117 1
      docs/spec.md
  39. 5 5
      go.mod
  40. 18 15
      go.sum
  41. 1 0
      hack/api-docs/mkdocs.yml
  42. 33 0
      hack/crd.generate.sh
  43. 33 0
      hack/helm.generate.sh
  44. 68 19
      pkg/provider/ibm/provider.go
  45. 13 0
      pkg/provider/ibm/provider_test.go
  46. 21 4
      pkg/provider/onepassword/fake/fake.go
  47. 7 14
      pkg/provider/onepassword/onepassword.go
  48. 1 1
      pkg/provider/onepassword/onepassword_test.go
  49. 3 0
      pkg/utils/utils.go

+ 2 - 36
Makefile

@@ -145,15 +145,7 @@ fmt: lint.check ## Ensure consistent code style
 	@$(OK) Ensured consistent code style
 
 generate: ## Generate code and crds
-	@go run sigs.k8s.io/controller-tools/cmd/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..."
-	@go run sigs.k8s.io/controller-tools/cmd/controller-gen crd paths="./..." output:crd:artifacts:config=$(CRD_DIR)/bases
-# Remove extra header lines in generated CRDs
-	@for i in $(CRD_DIR)/bases/*.yaml; do \
-  		tail -n +2 <"$$i" >"$$i.bkp" && \
-  		cp "$$i.bkp" "$$i" && \
-  		rm "$$i.bkp"; \
-  	done
-	@yq e '.spec.conversion.strategy = "Webhook" | .spec.conversion.webhook.conversionReviewVersions = ["v1"] | .spec.conversion.webhook.clientConfig.service.name = "kubernetes" | .spec.conversion.webhook.clientConfig.service.namespace = "default" |	.spec.conversion.webhook.clientConfig.service.path = "/convert"' $(CRD_DIR)/bases/*  > $(BUNDLE_DIR)/bundle.yaml
+	@./hack/crd.generate.sh $(BUNDLE_DIR) $(CRD_DIR)
 	@$(OK) Finished generating deepcopy and crds
 
 # ====================================================================================
@@ -190,33 +182,7 @@ helm.build: helm.generate ## Build helm chart
 	@$(OK) helm package
 
 helm.generate:
-# Split the generated bundle yaml file to inject control flags
-	@for i in $(BUNDLE_DIR)/*.yaml; do \
-		yq e -Ns '"$(HELM_DIR)/templates/crds/" + .spec.names.singular' "$$i"; \
-	done
-# Add helm if statement for controlling the install of CRDs
-	@for i in $(HELM_DIR)/templates/crds/*.yml; do \
-		export CRDS_FLAG_NAME="create$$(yq e '.spec.names.kind' $$i)"; \
-		cp "$$i" "$$i.bkp"; \
-		if [[ "$$CRDS_FLAG_NAME" == *"Cluster"* ]]; then \
-			echo "{{- if and (.Values.installCRDs) (.Values.crds.$$CRDS_FLAG_NAME) }}" > "$$i"; \
-		elif [[ "$$CRDS_FLAG_NAME" == *"PushSecret"* ]]; then \
-			echo "{{- if and (.Values.installCRDs) (.Values.crds.$$CRDS_FLAG_NAME) }}" > "$$i"; \
-		else \
-			echo "{{- if .Values.installCRDs }}" > "$$i"; \
-		fi; \
-		cat "$$i.bkp" >> "$$i" && \
-		echo "{{- end }}" >> "$$i" && \
-		rm "$$i.bkp" && \
-		if [[ "$$OSTYPE" == "darwin"* ]]; then \
-		  SEDPRG="gsed"; \
-		else \
-		  SEDPRG="sed"; \
-		fi; \
-		$$SEDPRG -i 's/name: kubernetes/name: {{ include "external-secrets.fullname" . }}-webhook/g' "$$i" && \
-		$$SEDPRG -i 's/namespace: default/namespace: {{ .Release.Namespace | quote }}/g' "$$i" && \
-		mv "$$i" "$${i%.yml}.yaml"; \
-	done
+	./hack/helm.generate.sh $(BUNDLE_DIR) $(HELM_DIR)
 	@$(OK) Finished generating helm chart files
 
 # ====================================================================================

+ 15 - 2
apis/externalsecrets/v1beta1/secretstore_ibm_types.go

@@ -28,12 +28,25 @@ type IBMProvider struct {
 	ServiceURL *string `json:"serviceUrl,omitempty"`
 }
 
+// +kubebuilder:validation:MinProperties=1
+// +kubebuilder:validation:MaxProperties=1
 type IBMAuth struct {
-	SecretRef IBMAuthSecretRef `json:"secretRef"`
+	SecretRef     IBMAuthSecretRef     `json:"secretRef,omitempty"`
+	ContainerAuth IBMAuthContainerAuth `json:"containerAuth,omitempty"`
 }
 
 type IBMAuthSecretRef struct {
 	// The SecretAccessKey is used for authentication
-	// +optional
 	SecretAPIKey esmeta.SecretKeySelector `json:"secretApiKeySecretRef,omitempty"`
 }
+
+// IBM Container-based auth with IAM Trusted Profile.
+type IBMAuthContainerAuth struct {
+	// the IBM Trusted Profile
+	Profile string `json:"profile"`
+
+	// Location the token is mounted on the pod
+	TokenLocation string `json:"tokenLocation,omitempty"`
+
+	IAMEndpoint string `json:"iamEndpoint,omitempty"`
+}

+ 28 - 0
apis/externalsecrets/v1beta1/secretstore_types.go

@@ -107,6 +107,34 @@ type SecretStoreProvider struct {
 	Senhasegura *SenhaseguraProvider `json:"senhasegura,omitempty"`
 }
 
+type CAProviderType string
+
+const (
+	CAProviderTypeSecret    CAProviderType = "Secret"
+	CAProviderTypeConfigMap CAProviderType = "ConfigMap"
+)
+
+// Used to provide custom certificate authority (CA) certificates
+// for a secret store. The CAProvider points to a Secret or ConfigMap resource
+// that contains a PEM-encoded certificate.
+type CAProvider struct {
+	// The type of provider to use such as "Secret", or "ConfigMap".
+	// +kubebuilder:validation:Enum="Secret";"ConfigMap"
+	Type CAProviderType `json:"type"`
+
+	// The name of the object located at the provider type.
+	Name string `json:"name"`
+
+	// The key where the CA certificate can be found in the Secret or ConfigMap.
+	// +kubebuilder:validation:Optional
+	Key string `json:"key,omitempty"`
+
+	// The namespace the Provider type is in.
+	// Can only be defined when used in a ClusterSecretStore.
+	// +optional
+	Namespace *string `json:"namespace,omitempty"`
+}
+
 type SecretStoreRetrySettings struct {
 	MaxRetries    *int32  `json:"maxRetries,omitempty"`
 	RetryInterval *string `json:"retryInterval,omitempty"`

+ 0 - 25
apis/externalsecrets/v1beta1/secretstore_vault_types.go

@@ -25,31 +25,6 @@ const (
 	VaultKVStoreV2 VaultKVStoreVersion = "v2"
 )
 
-type CAProviderType string
-
-const (
-	CAProviderTypeSecret    CAProviderType = "Secret"
-	CAProviderTypeConfigMap CAProviderType = "ConfigMap"
-)
-
-// Defines a location to fetch the cert for the vault provider from.
-type CAProvider struct {
-	// The type of provider to use such as "Secret", or "ConfigMap".
-	// +kubebuilder:validation:Enum="Secret";"ConfigMap"
-	Type CAProviderType `json:"type"`
-
-	// The name of the object located at the provider type.
-	Name string `json:"name"`
-
-	// The key the value inside of the provider type to use, only used with "Secret" type
-	// +kubebuilder:validation:Optional
-	Key string `json:"key,omitempty"`
-
-	// The namespace the Provider type is in.
-	// +optional
-	Namespace *string `json:"namespace,omitempty"`
-}
-
 // Configures an store to sync secrets using a HashiCorp Vault
 // KV backend.
 type VaultProvider struct {

+ 16 - 0
apis/externalsecrets/v1beta1/zz_generated.deepcopy.go

@@ -1035,6 +1035,7 @@ func (in *GitlabSecretRef) DeepCopy() *GitlabSecretRef {
 func (in *IBMAuth) DeepCopyInto(out *IBMAuth) {
 	*out = *in
 	in.SecretRef.DeepCopyInto(&out.SecretRef)
+	out.ContainerAuth = in.ContainerAuth
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IBMAuth.
@@ -1047,6 +1048,21 @@ func (in *IBMAuth) DeepCopy() *IBMAuth {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *IBMAuthContainerAuth) DeepCopyInto(out *IBMAuthContainerAuth) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IBMAuthContainerAuth.
+func (in *IBMAuthContainerAuth) DeepCopy() *IBMAuthContainerAuth {
+	if in == nil {
+		return nil
+	}
+	out := new(IBMAuthContainerAuth)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *IBMAuthSecretRef) DeepCopyInto(out *IBMAuthSecretRef) {
 	*out = *in

+ 32 - 18
cmd/root.go

@@ -51,8 +51,12 @@ var (
 	healthzAddr                           string
 	controllerClass                       string
 	enableLeaderElection                  bool
+	enableSecretsCache                    bool
+	enableConfigMapsCache                 bool
 	concurrent                            int
 	port                                  int
+	clientQPS                             float32
+	clientBurst                           int
 	loglevel                              string
 	namespace                             string
 	enableClusterStoreReconciler          bool
@@ -85,6 +89,19 @@ var rootCmd = &cobra.Command{
 	Long:  `For more information visit https://external-secrets.io`,
 	Run: func(cmd *cobra.Command, args []string) {
 		var lvl zapcore.Level
+		// the client creates a ListWatch for all resource kinds that
+		// are requested with .Get().
+		// We want to avoid to cache all secrets or configmaps in memory.
+		// The ES controller uses v1.PartialObjectMetadata for the secrets
+		// that he owns.
+		// see #721
+		cacheList := make([]client.Object, 0)
+		if !enableSecretsCache {
+			cacheList = append(cacheList, &v1.Secret{})
+		}
+		if !enableConfigMapsCache {
+			cacheList = append(cacheList, &v1.ConfigMap{})
+		}
 		err := lvl.UnmarshalText([]byte(loglevel))
 		if err != nil {
 			setupLog.Error(err, "error unmarshalling loglevel")
@@ -92,24 +109,17 @@ var rootCmd = &cobra.Command{
 		}
 		logger := zap.New(zap.Level(lvl))
 		ctrl.SetLogger(logger)
-
-		mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
-			Scheme:             scheme,
-			MetricsBindAddress: metricsAddr,
-			Port:               9443,
-			LeaderElection:     enableLeaderElection,
-			LeaderElectionID:   "external-secrets-controller",
-			ClientDisableCacheFor: []client.Object{
-				// the client creates a ListWatch for all resource kinds that
-				// are requested with .Get().
-				// We want to avoid to cache all secrets or configmaps in memory.
-				// The ES controller uses v1.PartialObjectMetadata for the secrets
-				// that he owns.
-				// see #721
-				&v1.Secret{},
-				&v1.ConfigMap{},
-			},
-			Namespace: namespace,
+		config := ctrl.GetConfigOrDie()
+		config.QPS = clientQPS
+		config.Burst = clientBurst
+		mgr, err := ctrl.NewManager(config, ctrl.Options{
+			Scheme:                scheme,
+			MetricsBindAddress:    metricsAddr,
+			Port:                  9443,
+			LeaderElection:        enableLeaderElection,
+			LeaderElectionID:      "external-secrets-controller",
+			ClientDisableCacheFor: cacheList,
+			Namespace:             namespace,
 		})
 		if err != nil {
 			setupLog.Error(err, "unable to start manager")
@@ -199,11 +209,15 @@ func init() {
 		"Enable leader election for controller manager. "+
 			"Enabling this will ensure there is only one active controller manager.")
 	rootCmd.Flags().IntVar(&concurrent, "concurrent", 1, "The number of concurrent ExternalSecret reconciles.")
+	rootCmd.Flags().Float32Var(&clientQPS, "client-qps", 0, "QPS configuration to be passed to rest.Client")
+	rootCmd.Flags().IntVar(&clientBurst, "client-burst", 0, "Maximum Burst allowed to be passed to rest.Client")
 	rootCmd.Flags().StringVar(&loglevel, "loglevel", "info", "loglevel to use, one of: debug, info, warn, error, dpanic, panic, fatal")
 	rootCmd.Flags().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")
 	rootCmd.Flags().BoolVar(&enableClusterStoreReconciler, "enable-cluster-store-reconciler", true, "Enable cluster store reconciler.")
 	rootCmd.Flags().BoolVar(&enableClusterExternalSecretReconciler, "enable-cluster-external-secret-reconciler", true, "Enable cluster external secret reconciler.")
 	rootCmd.Flags().BoolVar(&enablePushSecretReconciler, "experimental-enable-push-secret-reconciler", false, "Enable push secret reconciler.")
+	rootCmd.Flags().BoolVar(&enableSecretsCache, "enable-secrets-caching", false, "Enable secrets caching for external-secrets pod.")
+	rootCmd.Flags().BoolVar(&enableConfigMapsCache, "enable-configmaps-caching", false, "Enable secrets caching for external-secrets pod.")
 	rootCmd.Flags().DurationVar(&storeRequeueInterval, "store-requeue-interval", time.Minute*5, "Default Time duration between reconciling (Cluster)SecretStores")
 	rootCmd.Flags().BoolVar(&enableFloodGate, "enable-flood-gate", true, "Enable flood gate. External secret will be reconciled only if the ClusterStore or Store have an healthy or unknown state.")
 	rootCmd.Flags().BoolVar(&enableAWSSession, "experimental-enable-aws-session-cache", false, "Enable experimental AWS session cache. External secret will reuse the AWS session without creating a new one on each request.")

+ 2 - 1
config/crds/bases/external-secrets.io_clusterexternalsecrets.yaml

@@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.9.0
+    controller-gen.kubebuilder.io/version: v0.9.2
   creationTimestamp: null
   name: clusterexternalsecrets.external-secrets.io
 spec:
@@ -344,6 +344,7 @@ spec:
                       are ANDed.
                     type: object
                 type: object
+                x-kubernetes-map-type: atomic
               refreshTime:
                 description: The time in which the controller should reconcile it's
                   objects and recheck namespaces for labels.

+ 26 - 8
config/crds/bases/external-secrets.io_clustersecretstores.yaml

@@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.9.0
+    controller-gen.kubebuilder.io/version: v0.9.2
   creationTimestamp: null
   name: clustersecretstores.external-secrets.io
 spec:
@@ -1908,7 +1908,25 @@ spec:
                       auth:
                         description: Auth configures how secret-manager authenticates
                           with the IBM secrets manager.
+                        maxProperties: 1
+                        minProperties: 1
                         properties:
+                          containerAuth:
+                            description: IBM Container-based auth with IAM Trusted
+                              Profile.
+                            properties:
+                              iamEndpoint:
+                                type: string
+                              profile:
+                                description: the IBM Trusted Profile
+                                type: string
+                              tokenLocation:
+                                description: Location the token is mounted on the
+                                  pod
+                                type: string
+                            required:
+                            - profile
+                            type: object
                           secretRef:
                             properties:
                               secretApiKeySecretRef:
@@ -1932,8 +1950,6 @@ spec:
                                     type: string
                                 type: object
                             type: object
-                        required:
-                        - secretRef
                         type: object
                       serviceUrl:
                         description: ServiceURL is the Endpoint URL that is specific
@@ -2058,8 +2074,8 @@ spec:
                             description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider'
                             properties:
                               key:
-                                description: The key the value inside of the provider
-                                  type to use, only used with "Secret" type
+                                description: The key where the CA certificate can
+                                  be found in the Secret or ConfigMap.
                                 type: string
                               name:
                                 description: The name of the object located at the
@@ -2067,6 +2083,7 @@ spec:
                                 type: string
                               namespace:
                                 description: The namespace the Provider type is in.
+                                  Can only be defined when used in a ClusterSecretStore.
                                 type: string
                               type:
                                 description: The type of provider to use such as "Secret",
@@ -2591,15 +2608,16 @@ spec:
                           Vault server certificate.
                         properties:
                           key:
-                            description: The key the value inside of the provider
-                              type to use, only used with "Secret" type
+                            description: The key where the CA certificate can be found
+                              in the Secret or ConfigMap.
                             type: string
                           name:
                             description: The name of the object located at the provider
                               type.
                             type: string
                           namespace:
-                            description: The namespace the Provider type is in.
+                            description: The namespace the Provider type is in. Can
+                              only be defined when used in a ClusterSecretStore.
                             type: string
                           type:
                             description: The type of provider to use such as "Secret",

+ 1 - 1
config/crds/bases/external-secrets.io_externalsecrets.yaml

@@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.9.0
+    controller-gen.kubebuilder.io/version: v0.9.2
   creationTimestamp: null
   name: externalsecrets.external-secrets.io
 spec:

+ 1 - 1
config/crds/bases/external-secrets.io_pushsecrets.yaml

@@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.9.0
+    controller-gen.kubebuilder.io/version: v0.9.2
   creationTimestamp: null
   name: pushsecrets.external-secrets.io
 spec:

+ 26 - 8
config/crds/bases/external-secrets.io_secretstores.yaml

@@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.9.0
+    controller-gen.kubebuilder.io/version: v0.9.2
   creationTimestamp: null
   name: secretstores.external-secrets.io
 spec:
@@ -1908,7 +1908,25 @@ spec:
                       auth:
                         description: Auth configures how secret-manager authenticates
                           with the IBM secrets manager.
+                        maxProperties: 1
+                        minProperties: 1
                         properties:
+                          containerAuth:
+                            description: IBM Container-based auth with IAM Trusted
+                              Profile.
+                            properties:
+                              iamEndpoint:
+                                type: string
+                              profile:
+                                description: the IBM Trusted Profile
+                                type: string
+                              tokenLocation:
+                                description: Location the token is mounted on the
+                                  pod
+                                type: string
+                            required:
+                            - profile
+                            type: object
                           secretRef:
                             properties:
                               secretApiKeySecretRef:
@@ -1932,8 +1950,6 @@ spec:
                                     type: string
                                 type: object
                             type: object
-                        required:
-                        - secretRef
                         type: object
                       serviceUrl:
                         description: ServiceURL is the Endpoint URL that is specific
@@ -2058,8 +2074,8 @@ spec:
                             description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider'
                             properties:
                               key:
-                                description: The key the value inside of the provider
-                                  type to use, only used with "Secret" type
+                                description: The key where the CA certificate can
+                                  be found in the Secret or ConfigMap.
                                 type: string
                               name:
                                 description: The name of the object located at the
@@ -2067,6 +2083,7 @@ spec:
                                 type: string
                               namespace:
                                 description: The namespace the Provider type is in.
+                                  Can only be defined when used in a ClusterSecretStore.
                                 type: string
                               type:
                                 description: The type of provider to use such as "Secret",
@@ -2591,15 +2608,16 @@ spec:
                           Vault server certificate.
                         properties:
                           key:
-                            description: The key the value inside of the provider
-                              type to use, only used with "Secret" type
+                            description: The key where the CA certificate can be found
+                              in the Secret or ConfigMap.
                             type: string
                           name:
                             description: The name of the object located at the provider
                               type.
                             type: string
                           namespace:
-                            description: The namespace the Provider type is in.
+                            description: The namespace the Provider type is in. Can
+                              only be defined when used in a ClusterSecretStore.
                             type: string
                           type:
                             description: The type of provider to use such as "Secret",

+ 8 - 0
config/crds/bases/kustomization.yaml

@@ -0,0 +1,8 @@
+---
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+resources:
+  - external-secrets.io_clusterexternalsecrets.yaml
+  - external-secrets.io_clustersecretstores.yaml
+  - external-secrets.io_externalsecrets.yaml
+  - external-secrets.io_secretstores.yaml

+ 10 - 0
deploy/charts/external-secrets/README.md

@@ -47,6 +47,9 @@ The command removes all the Kubernetes components associated with the chart and
 | certController.image.repository | string | `"ghcr.io/external-secrets/external-secrets"` |  |
 | certController.image.tag | string | `""` |  |
 | certController.imagePullSecrets | list | `[]` |  |
+| certController.metrics.service.annotations | object | `{}` | Additional service annotations |
+| certController.metrics.service.enabled | bool | `false` | Enable if you use another monitoring tool than Prometheus to scrape the metrics |
+| certController.metrics.service.port | int | `8080` | Metrics service port to scrape |
 | certController.nameOverride | string | `""` |  |
 | certController.nodeSelector | object | `{}` |  |
 | certController.podAnnotations | object | `{}` | Annotations to add to Pod |
@@ -76,6 +79,7 @@ The command removes all the Kubernetes components associated with the chart and
 | crds.createClusterSecretStore | bool | `true` | If true, create CRDs for Cluster Secret Store. |
 | createOperator | bool | `true` | Specifies whether an external secret operator deployment be created. |
 | deploymentAnnotations | object | `{}` | Annotations to add to Deployment |
+| dnsConfig | object | `{}` | Specifies `dnsOptions` to deployment |
 | extraArgs | object | `{}` |  |
 | extraEnv | list | `[]` |  |
 | extraVolumeMounts | list | `[]` |  |
@@ -87,6 +91,9 @@ The command removes all the Kubernetes components associated with the chart and
 | imagePullSecrets | list | `[]` |  |
 | installCRDs | bool | `true` | If set, install and upgrade CRDs through helm chart. |
 | leaderElect | bool | `false` | If true, external-secrets will perform leader election between instances to ensure no more than one instance of external-secrets operates at a time. |
+| metrics.service.annotations | object | `{}` | Additional service annotations |
+| metrics.service.enabled | bool | `false` | Enable if you use another monitoring tool than Prometheus to scrape the metrics |
+| metrics.service.port | int | `8080` | Metrics service port to scrape |
 | nameOverride | string | `""` |  |
 | nodeSelector | object | `{}` |  |
 | podAnnotations | object | `{}` | Annotations to add to Pod |
@@ -130,6 +137,9 @@ The command removes all the Kubernetes components associated with the chart and
 | webhook.image.tag | string | `""` | The image tag to use. The default is the chart appVersion. |
 | webhook.imagePullSecrets | list | `[]` |  |
 | webhook.lookaheadInterval | string | `""` | Specifices the lookaheadInterval for certificate validity |
+| webhook.metrics.service.annotations | object | `{}` | Additional service annotations |
+| webhook.metrics.service.enabled | bool | `false` | Enable if you use another monitoring tool than Prometheus to scrape the metrics |
+| webhook.metrics.service.port | int | `8080` | Metrics service port to scrape |
 | webhook.nameOverride | string | `""` |  |
 | webhook.nodeSelector | object | `{}` |  |
 | webhook.podAnnotations | object | `{}` | Annotations to add to Pod |

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

@@ -1,4 +1,3 @@
-{{- $valuesYAML := "https://github.com/external-secrets/external-secrets/blob/master/deploy/charts/external-secrets/values.yaml" -}}
 {{- $chartRepo := "https://charts.external-secrets.io" -}}
 {{- $org := "external-secrets" -}}
 # External Secrets

+ 13 - 2
deploy/charts/external-secrets/templates/cert-controller-service.yaml

@@ -1,20 +1,31 @@
-{{- if and .Values.certController.create .Values.certController.prometheus.enabled }}
+{{- if or (and .Values.certController.create .Values.certController.prometheus.enabled) (and .Values.certController.create .Values.certController.metrics.service.enabled) }}
 apiVersion: v1
 kind: Service
 metadata:
   name: {{ include "external-secrets.fullname" . }}-cert-controller-metrics
   labels:
     {{- include "external-secrets.labels" . | nindent 4 }}
+  {{- if .Values.certController.prometheus.enabled }}
   annotations:
     prometheus.io/path: "/metrics"
     prometheus.io/scrape: "true"
     prometheus.io/port: {{ .Values.certController.prometheus.service.port | quote }}
+  {{- else }}
+  {{- with .Values.metrics.service.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+  {{- end }}
 spec:
   type: ClusterIP
   ports:
+  {{- if .Values.certController.prometheus.enabled }}
   - port: {{ .Values.certController.prometheus.service.port }}
+  {{- else }}
+  - port: {{ .Values.certController.metrics.service.port }}
+  {{- end }}
     protocol: TCP
     name: metrics
   selector:
     {{- include "external-secrets-cert-controller.selectorLabels" . | nindent 4 }}
-{{- end }}
+{{- end }}

+ 4 - 0
deploy/charts/external-secrets/templates/deployment.yaml

@@ -93,6 +93,10 @@ spec:
           volumeMounts:
           {{- toYaml .Values.extraVolumeMounts | nindent 12 }}
           {{- end }}
+      {{- if .Values.dnsConfig }}
+      dnsConfig:
+          {{- toYaml .Values.dnsConfig | nindent 8 }}
+      {{- end }}
       {{- if .Values.extraVolumes }}
       volumes:
       {{- toYaml .Values.extraVolumes | nindent 8 }}

+ 13 - 2
deploy/charts/external-secrets/templates/service.yaml

@@ -1,4 +1,4 @@
-{{- if .Values.prometheus.enabled }}
+{{- if or .Values.prometheus.enabled .Values.metrics.service.enabled }}
 apiVersion: v1
 kind: Service
 metadata:
@@ -6,16 +6,27 @@ metadata:
   namespace: {{ .Release.Namespace | quote }}
   labels:
     {{- include "external-secrets.labels" . | nindent 4 }}
+  {{- if .Values.prometheus.enabled }}
   annotations:
     prometheus.io/path: "/metrics"
     prometheus.io/scrape: "true"
     prometheus.io/port: {{ .Values.prometheus.service.port | quote }}
+  {{- else }}
+  {{- with .Values.metrics.service.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+  {{- end }}
 spec:
   type: ClusterIP
   ports:
+    {{- if .Values.prometheus.enabled }}
     - port: {{ .Values.prometheus.service.port }}
+    {{- else }}
+    - port: {{ .Values.metrics.service.port }}
+    {{- end }}
       protocol: TCP
       name: metrics
   selector:
     {{- include "external-secrets.selectorLabels" . | nindent 4 }}
-{{- end }}
+{{- end }}

+ 14 - 4
deploy/charts/external-secrets/templates/webhook-service.yaml

@@ -12,6 +12,11 @@ metadata:
     prometheus.io/path: "/metrics"
     prometheus.io/scrape: "true"
     prometheus.io/port: {{ .Values.prometheus.service.port | quote }}
+  {{- else }}
+  {{- with .Values.metrics.service.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
   {{- end }}
 spec:
   type: ClusterIP
@@ -20,12 +25,17 @@ spec:
     targetPort: {{ .Values.webhook.port }}
     protocol: TCP
     name: webhook
-  {{- if .Values.webhook.prometheus.enabled}}
-  - port: {{ .Values.webhook.prometheus.service.port}}
-    targetPort: {{ .Values.webhook.prometheus.service.port}}
+  {{- if or .Values.webhook.prometheus.enabled .Values.webhook.metrics.service.enabled }}
+  {{- if .Values.webhook.prometheus.enabled }}
+  - port: {{ .Values.webhook.prometheus.service.port }}
+    targetPort: {{ .Values.webhook.prometheus.service.port }}
+  {{- else }}
+  - port: {{ .Values.webhook.metrics.service.port }}
+    targetPort: {{ .Values.webhook.metrics.service.port }}
+  {{- end }}
     protocol: TCP
     name: metrics
   {{- end }}
   selector:
     {{- include "external-secrets-webhook.selectorLabels" . | nindent 4 }}
-{{- end }}
+{{- end }}

+ 37 - 0
deploy/charts/external-secrets/values.yaml

@@ -121,6 +121,17 @@ serviceMonitor:
   # -- Timeout if metrics can't be retrieved in given time interval
   scrapeTimeout: 25s
 
+metrics:
+  service:
+    # -- Enable if you use another monitoring tool than Prometheus to scrape the metrics
+    enabled: false
+
+    # -- Metrics service port to scrape
+    port: 8080
+
+    # -- Additional service annotations
+    annotations: {}
+
 nodeSelector: {}
 
 tolerations: []
@@ -206,6 +217,17 @@ webhook:
     # -- Timeout if metrics can't be retrieved in given time interval
     scrapeTimeout: 25s
 
+  metrics:
+    service:
+      # -- Enable if you use another monitoring tool than Prometheus to scrape the metrics
+      enabled: false
+
+      # -- Metrics service port to scrape
+      port: 8080
+
+      # -- Additional service annotations
+      annotations: {}
+
     ## -- Extra environment variables to add to container.
   extraEnv: []
 
@@ -305,12 +327,24 @@ certController:
     # -- Timeout if metrics can't be retrieved in given time interval
     scrapeTimeout: 25s
 
+  metrics:
+    service:
+      # -- Enable if you use another monitoring tool than Prometheus to scrape the metrics
+      enabled: false
+
+      # -- Metrics service port to scrape
+      port: 8080
+
+      # -- Additional service annotations
+      annotations: {}
+
     ## -- Extra environment variables to add to container.
   extraEnv: []
 
     ## -- Map of extra arguments to pass to container.
   extraArgs: {}
 
+
     ## -- Extra volumes to pass to pod.
   extraVolumes: []
 
@@ -340,3 +374,6 @@ certController:
       # requests:
       #   cpu: 10m
       #   memory: 32Mi
+
+# -- Specifies `dnsOptions` to deployment
+dnsConfig: {}

+ 46 - 17
deploy/crds/bundle.yaml

@@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.9.0
+    controller-gen.kubebuilder.io/version: v0.9.2
   creationTimestamp: null
   name: clusterexternalsecrets.external-secrets.io
 spec:
@@ -294,6 +294,7 @@ spec:
                       description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
                       type: object
                   type: object
+                  x-kubernetes-map-type: atomic
                 refreshTime:
                   description: The time in which the controller should reconcile it's objects and recheck namespaces for labels.
                   type: string
@@ -359,7 +360,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.9.0
+    controller-gen.kubebuilder.io/version: v0.9.2
   creationTimestamp: null
   name: clustersecretstores.external-secrets.io
 spec:
@@ -1774,7 +1775,23 @@ spec:
                       properties:
                         auth:
                           description: Auth configures how secret-manager authenticates with the IBM secrets manager.
+                          maxProperties: 1
+                          minProperties: 1
                           properties:
+                            containerAuth:
+                              description: IBM Container-based auth with IAM Trusted Profile.
+                              properties:
+                                iamEndpoint:
+                                  type: string
+                                profile:
+                                  description: the IBM Trusted Profile
+                                  type: string
+                                tokenLocation:
+                                  description: Location the token is mounted on the pod
+                                  type: string
+                              required:
+                                - profile
+                              type: object
                             secretRef:
                               properties:
                                 secretApiKeySecretRef:
@@ -1791,8 +1808,6 @@ spec:
                                       type: string
                                   type: object
                               type: object
-                          required:
-                            - secretRef
                           type: object
                         serviceUrl:
                           description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance
@@ -1883,13 +1898,13 @@ spec:
                               description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider'
                               properties:
                                 key:
-                                  description: The key the value inside of the provider type to use, only used with "Secret" type
+                                  description: The key where the CA certificate can be found in the Secret or ConfigMap.
                                   type: string
                                 name:
                                   description: The name of the object located at the provider type.
                                   type: string
                                 namespace:
-                                  description: The namespace the Provider type is in.
+                                  description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore.
                                   type: string
                                 type:
                                   description: The type of provider to use such as "Secret", or "ConfigMap".
@@ -2255,13 +2270,13 @@ spec:
                           description: The provider for the CA bundle to use to validate Vault server certificate.
                           properties:
                             key:
-                              description: The key the value inside of the provider type to use, only used with "Secret" type
+                              description: The key where the CA certificate can be found in the Secret or ConfigMap.
                               type: string
                             name:
                               description: The name of the object located at the provider type.
                               type: string
                             namespace:
-                              description: The namespace the Provider type is in.
+                              description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore.
                               type: string
                             type:
                               description: The type of provider to use such as "Secret", or "ConfigMap".
@@ -2529,7 +2544,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.9.0
+    controller-gen.kubebuilder.io/version: v0.9.2
   creationTimestamp: null
   name: externalsecrets.external-secrets.io
 spec:
@@ -3051,7 +3066,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.9.0
+    controller-gen.kubebuilder.io/version: v0.9.2
   creationTimestamp: null
   name: pushsecrets.external-secrets.io
 spec:
@@ -3197,7 +3212,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.9.0
+    controller-gen.kubebuilder.io/version: v0.9.2
   creationTimestamp: null
   name: secretstores.external-secrets.io
 spec:
@@ -4612,7 +4627,23 @@ spec:
                       properties:
                         auth:
                           description: Auth configures how secret-manager authenticates with the IBM secrets manager.
+                          maxProperties: 1
+                          minProperties: 1
                           properties:
+                            containerAuth:
+                              description: IBM Container-based auth with IAM Trusted Profile.
+                              properties:
+                                iamEndpoint:
+                                  type: string
+                                profile:
+                                  description: the IBM Trusted Profile
+                                  type: string
+                                tokenLocation:
+                                  description: Location the token is mounted on the pod
+                                  type: string
+                              required:
+                                - profile
+                              type: object
                             secretRef:
                               properties:
                                 secretApiKeySecretRef:
@@ -4629,8 +4660,6 @@ spec:
                                       type: string
                                   type: object
                               type: object
-                          required:
-                            - secretRef
                           type: object
                         serviceUrl:
                           description: ServiceURL is the Endpoint URL that is specific to the Secrets Manager service instance
@@ -4721,13 +4750,13 @@ spec:
                               description: 'see: https://external-secrets.io/v0.4.1/spec/#external-secrets.io/v1alpha1.CAProvider'
                               properties:
                                 key:
-                                  description: The key the value inside of the provider type to use, only used with "Secret" type
+                                  description: The key where the CA certificate can be found in the Secret or ConfigMap.
                                   type: string
                                 name:
                                   description: The name of the object located at the provider type.
                                   type: string
                                 namespace:
-                                  description: The namespace the Provider type is in.
+                                  description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore.
                                   type: string
                                 type:
                                   description: The type of provider to use such as "Secret", or "ConfigMap".
@@ -5093,13 +5122,13 @@ spec:
                           description: The provider for the CA bundle to use to validate Vault server certificate.
                           properties:
                             key:
-                              description: The key the value inside of the provider type to use, only used with "Secret" type
+                              description: The key where the CA certificate can be found in the Secret or ConfigMap.
                               type: string
                             name:
                               description: The name of the object located at the provider type.
                               type: string
                             namespace:
-                              description: The namespace the Provider type is in.
+                              description: The namespace the Provider type is in. Can only be defined when used in a ClusterSecretStore.
                               type: string
                             type:
                               description: The type of provider to use such as "Secret", or "ConfigMap".

+ 2 - 0
docs/guides-metrics.md

@@ -2,6 +2,8 @@
 
 The External Secrets Operator exposes its Prometheus metrics in the `/metrics` path. To enable it, set the `serviceMonitor.enabled` Helm flag to `true`. In addition you can also set `webhook.serviceMonitor.enabled=true` and `certController.serviceMonitor.enabled=true` to create `ServiceMonitor` resources for the other components.
 
+If you are using a different monitoring tool that also needs a `/metrics` endpoint, you can set the `metrics.service.enabled` Helm flag to `true`. In addition you can also set `webhook.metrics.service.enabled` and `certController.metrics.service.enabled` to scrape the other components.
+
 The Operator has the metrics inherited from Kubebuilder plus some custom metrics with the `externalsecret` prefix.
 
 ## External Secret Metrics

BIN
docs/pictures/screenshot_container_auth_create_1.png


BIN
docs/pictures/screenshot_container_auth_create_2.png


BIN
docs/pictures/screenshot_container_auth_create_3.png


BIN
docs/pictures/screenshot_container_auth_create_button.png


BIN
docs/pictures/screenshot_container_auth_create_group.png


BIN
docs/pictures/screenshot_container_auth_create_group_1.png


BIN
docs/pictures/screenshot_container_auth_create_group_2.png


BIN
docs/pictures/screenshot_container_auth_create_group_3.png


BIN
docs/pictures/screenshot_container_auth_create_group_4.png


BIN
docs/pictures/screenshot_container_auth_iam_left.png


+ 1 - 1
docs/provider-1password-automation.md

@@ -32,7 +32,7 @@ _**The 1Password API calls the entries in vaults 'Items'. These docs use the sam
     * External Secrets does not run this server. See [Deploy a Connect Server](#deploy-a-connect-server).
     * One Connect Server is needed per 1Password Automation Environment.
     * Many Vaults can be added to an Automation Environment, and Tokens can be generated in that Environment with access to any set or subset of those Vaults.
-* 1Password Connect Server version 1.3.0 or higher. 1.3.0 and 1.5.0 have been tested.
+* 1Password Connect Server version 1.5.6 or higher.
 
 ### Setup Authentication
 _Authentication requires a `1password-credentials.json` file provided to the Connect Server, and a related 'Access Token' for the client in this provider to authenticate to that Connect Server. Both of these are generated by 1Password._

+ 21 - 7
docs/provider-azure-key-vault.md

@@ -11,6 +11,13 @@ We support Service Principals, Managed Identity and Workload Identity authentica
 
 To use Managed Identity authentication, you should use [aad-pod-identity](https://azure.github.io/aad-pod-identity/docs/) to assign the identity to external-secrets operator. To add the selector to external-secrets operator, use `podLabels` in your values.yaml in case of Helm installation of external-secrets.
 
+Minimum required permissions are `Get` over secret and certificate permissions. This can be done by adding a Key Vault access policy:
+
+```sh
+KUBELET_IDENTITY_OBJECT_ID=$(az aks show --resource-group <AKS_CLUSTER_RG_NAME> --name <AKS_CLUSTER_NAME> --query 'identityProfile.kubeletidentity.objectId' -o tsv)
+az keyvault set-policy --name kv-name-with-certs --object-id "$KUBELET_IDENTITY_OBJECT_ID" --certificate-permissions get --secret-permissions get
+```
+
 #### Service Principal key authentication
 
 A service Principal client and Secret is created and the JSON keyfile is stored in a `Kind=Secret`. The `ClientID` and `ClientSecret` should be configured for the secret. This service principal should have proper access rights to the keyvault to be managed by the operator
@@ -89,23 +96,30 @@ Azure KeyVault manages different [object types](https://docs.microsoft.com/en-us
 | `key`         | A JWK which contains the public key. Azure KeyVault does **not** export the private key. You may want to use [template functions](guides-templating.md) to transform this JWK into PEM encoded PKIX ASN.1 DER format. |
 | `certificate` | The raw CER contents of the x509 certificate. You may want to use [template functions](guides-templating.md) to transform this into your desired encoding                                                             |
 
-
 ### Creating external secret
 
 To create a kubernetes secret from the Azure Key vault secret a `Kind=ExternalSecret` is needed.
 
-You can manage keys/secrets/certificates saved inside the keyvault , by setting a "/" prefixed type in the secret name , the default type is a `secret`. other supported values are `cert` and `key`
-
-to select all secrets inside the key vault or all tags inside a secret, you can use the `dataFrom` directive
+You can manage keys/secrets/certificates saved inside the keyvault , by setting a "/" prefixed type in the secret name, the default type is a `secret`. Other supported values are `cert` and `key`.
 
 ```yaml
 {% include 'azkv-external-secret.yaml' %}
 ```
+
+The operator will fetch the Azure Key vault secret and inject it as a `Kind=Secret`. Then the Kubernetes secret can be fetched by issuing:
+
+```sh
+kubectl get secret secret-to-be-created -n <namespace> | -o jsonpath='{.data.dev-secret-test}' | base64 -d
+```
+
+To select all secrets inside the key vault or all tags inside a secret, you can use the `dataFrom` directive:
+
 ```yaml
 {% include 'azkv-datafrom-external-secret.yaml' %}
 ```
 
-The operator will fetch the Azure Key vault secret and inject it as a `Kind=Secret`
+To get a PKCS#12 certificate from Azure Key Vault and inject it as a `Kind=Secret` of type `kubernetes.io/tls`:
+
+```yaml
+{% include 'azkv-pkcs12-cert-external-secret.yaml' %}
 ```
-kubectl get secret secret-to-be-created -n <namespace> | -o jsonpath='{.data.dev-secret-test}' | base64 -d
-```

+ 66 - 7
docs/provider-ibm-secrets-manager.md

@@ -4,7 +4,11 @@ External Secrets Operator integrates with [IBM Secret Manager](https://www.ibm.c
 
 ### Authentication
 
-At the moment, we only support API key authentication for this provider. To generate your key (for test purposes we are going to generate from your user), first got to your (Access IAM) page:
+We support API key and trusted profile container authentication for this provider.
+
+#### API key secret
+
+To generate your key (for test purposes we are going to generate from your user), first got to your (Access IAM) page:
 
 ![iam](./pictures/screenshot_api_keys_iam.png)
 
@@ -24,16 +28,68 @@ You have created a key. Press the eyeball to show the key. Copy or save it becau
 
 ![iam-create-success](./pictures/screenshot_api_keys_create_successful.png)
 
-
-
-#### API key secret
-
 Create a secret containing your apiKey:
 
 ```shell
 kubectl create secret generic ibm-secret --from-literal=apiKey='API_KEY_VALUE'
 ```
 
+#### Trusted Profile Container Auth
+
+To create the trusted profile, first got to your (Access IAM) page:
+
+![iam](./pictures/screenshot_api_keys_iam.png)
+
+On the left, click "Access groups":
+
+![iam-left](./pictures/screenshot_container_auth_create_group.png)
+
+Pick a name and description for your group:
+
+![iam-left](./pictures/screenshot_container_auth_create_group_1.png)
+
+Click on "Access Policies":
+
+![iam-left](./pictures/screenshot_container_auth_create_group_2.png)
+
+Click on "Assign Access", select "IAM services", and pick "Secrets Manager" from the pick-list:
+
+![iam-left](./pictures/screenshot_container_auth_create_group_3.png)
+
+Scope to "All resources" or "Resources based on selected attributes", select "SecretsReader":
+
+![iam-left](./pictures/screenshot_container_auth_create_group_4.png)
+
+Click "Add" and "Assign" to save the access group.
+
+Next, on the left, click "Trusted profiles":
+
+![iam-left](./pictures/screenshot_container_auth_iam_left.png)
+
+Press "Create":
+
+![iam-create-button](./pictures/screenshot_container_auth_create_button.png)
+
+Pick a name and description for your profile:
+
+![iam-create-key](./pictures/screenshot_container_auth_create_1.png)
+
+Scope the profile's access.
+
+The compute service type will be "Red Hat OpenShift on IBM Cloud".  Additional restriction can be configured based on cloud or cluster metadata, or if "Specific resources" is selected, restriction to a specific cluster.
+
+![iam-create-key](./pictures/screenshot_container_auth_create_2.png)
+
+Click "Add" next to the previously created access group and then "Create", to associate the necessary service permissions.
+
+![iam-create-key](./pictures/screenshot_container_auth_create_3.png)
+
+To use the container-based authentication, it is necessary to map the API server `serviceAccountToken` auth token to the "external-secrets" and "external-secrets-webhook" deployment descriptors. Example below:
+
+```yaml
+{% include 'ibm-container-auth-volume.yaml' %}
+```
+
 ### Update secret store
 Be sure the `ibm` provider is listed in the `Kind=SecretStore`
 
@@ -42,6 +98,9 @@ Be sure the `ibm` provider is listed in the `Kind=SecretStore`
 ```
 **NOTE:** In case of a `ClusterSecretStore`, Be sure to provide `namespace` in `secretApiKeySecretRef` with the namespace where the secret resides.
 
+**NOTE:** Only `secretApiKeySecretRef` or `containerAuth` should be specified, depending on authentication me
+thod being used.
+
 To find your serviceURL, under your Secrets Manager resource, go to "Endpoints" on the left.
 Note: Use the url without the `/api` suffix that is presented in the UI.
 See here for a list of [publicly available endpoints](https://cloud.ibm.com/apidocs/secrets-manager#getting-started-endpoints).
@@ -51,13 +110,13 @@ See here for a list of [publicly available endpoints](https://cloud.ibm.com/apid
 ### Secret Types
 We support the following secret types of [IBM Secrets Manager](https://cloud.ibm.com/apidocs/secrets-manager):
 
-* `arbitrary`
+* `arbitrary` 
 * `username_password`
 * `iam_credentials`
 * `imported_cert`
 * `public_cert`
 * `private_cert`
-* `kv`
+* `kv` 
 
 To define the type of secret you would like to sync you need to prefix the secret id with the desired type. If the secret type is not specified it is defaulted to `arbitrary`:
 

+ 24 - 0
docs/snippets/azkv-pkcs12-cert-external-secret.yaml

@@ -0,0 +1,24 @@
+{% raw %}
+apiVersion: external-secrets.io/v1beta1
+kind: ExternalSecret
+metadata:
+  name: mycert
+spec:
+  refreshInterval: 24h
+  secretStoreRef:
+    kind: ClusterSecretStore
+    name: kv-mycert
+  target:
+    template:
+      type: kubernetes.io/tls
+      engineVersion: v2
+      data:
+        tls.crt: "{{ .mycert | b64dec | pkcs12cert }}"
+        tls.key: "{{ .mycert | b64dec | pkcs12key }}"
+  data:
+  - secretKey: mycert
+    remoteRef:
+      # Azure Key Vault certificates must be fetched as secret/cert-name
+      key: secret/mycert
+
+{% endraw %}

+ 22 - 0
docs/snippets/ibm-container-auth-volume.yaml

@@ -0,0 +1,22 @@
+...
+spec:
+  ...
+  template:
+    ...
+    spec:
+      containers:
+        ...
+        volumeMounts:
+        - mountPath: /var/run/secrets/tokens
+           name: sa-token
+      ...
+      volumes:
+      - name: sa-token
+        projected:
+          defaultMode: 420
+          sources:
+          - serviceAccountToken:
+              audience: iam
+              expirationSeconds: 3600
+              path: sa-token
+...

+ 4 - 0
docs/snippets/ibm-secret-store.yaml

@@ -7,6 +7,10 @@ spec:
     ibm:
       serviceUrl: "https://SECRETS_MANAGER_ID.REGION.secrets-manager.appdomain.cloud"
       auth:
+        containerAuth:
+          profile: "test container auth profile"
+          tokenLocation: "/var/run/secrets/tokens/sa-token"
+          iamEndpoint: "https://iam.cloud.ibm.com"
         secretRef:
           secretApiKeySecretRef:
             name: ibm-secret

+ 117 - 1
docs/spec.md

@@ -1602,8 +1602,48 @@ ExternalSecretConversionStrategy
 <p>Used to define a conversion Strategy</p>
 </td>
 </tr>
+<tr>
+<td>
+<code>decodingStrategy</code></br>
+<em>
+<a href="#external-secrets.io/v1beta1.ExternalSecretDecodingStrategy">
+ExternalSecretDecodingStrategy
+</a>
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>Used to define a conversion Strategy</p>
+</td>
+</tr>
 </tbody>
 </table>
+<h3 id="external-secrets.io/v1beta1.ExternalSecretDecodingStrategy">ExternalSecretDecodingStrategy
+(<code>string</code> alias)</p></h3>
+<p>
+(<em>Appears on:</em>
+<a href="#external-secrets.io/v1beta1.ExternalSecretDataRemoteRef">ExternalSecretDataRemoteRef</a>, 
+<a href="#external-secrets.io/v1beta1.ExternalSecretFind">ExternalSecretFind</a>)
+</p>
+<p>
+</p>
+<table>
+<thead>
+<tr>
+<th>Value</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody><tr><td><p>&#34;Auto&#34;</p></td>
+<td></td>
+</tr><tr><td><p>&#34;Base64&#34;</p></td>
+<td></td>
+</tr><tr><td><p>&#34;Base64URL&#34;</p></td>
+<td></td>
+</tr><tr><td><p>&#34;None&#34;</p></td>
+<td></td>
+</tr></tbody>
+</table>
 <h3 id="external-secrets.io/v1beta1.ExternalSecretDeletionPolicy">ExternalSecretDeletionPolicy
 (<code>string</code> alias)</p></h3>
 <p>
@@ -1707,6 +1747,20 @@ ExternalSecretConversionStrategy
 <p>Used to define a conversion Strategy</p>
 </td>
 </tr>
+<tr>
+<td>
+<code>decodingStrategy</code></br>
+<em>
+<a href="#external-secrets.io/v1beta1.ExternalSecretDecodingStrategy">
+ExternalSecretDecodingStrategy
+</a>
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+<p>Used to define a conversion Strategy</p>
+</td>
+</tr>
 </tbody>
 </table>
 <h3 id="external-secrets.io/v1beta1.ExternalSecretMetadataPolicy">ExternalSecretMetadataPolicy
@@ -2615,6 +2669,69 @@ IBMAuthSecretRef
 <td>
 </td>
 </tr>
+<tr>
+<td>
+<code>containerAuth</code></br>
+<em>
+<a href="#external-secrets.io/v1beta1.IBMAuthContainerAuth">
+IBMAuthContainerAuth
+</a>
+</em>
+</td>
+<td>
+</td>
+</tr>
+</tbody>
+</table>
+<h3 id="external-secrets.io/v1beta1.IBMAuthContainerAuth">IBMAuthContainerAuth
+</h3>
+<p>
+(<em>Appears on:</em>
+<a href="#external-secrets.io/v1beta1.IBMAuth">IBMAuth</a>)
+</p>
+<p>
+<p>IBM Container-based auth with IAM Trusted Profile.</p>
+</p>
+<table>
+<thead>
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<code>profile</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+<p>the IBM Trusted Profile</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>tokenLocation</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+<p>Location the token is mounted on the pod</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>iamEndpoint</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+</td>
+</tr>
 </tbody>
 </table>
 <h3 id="external-secrets.io/v1beta1.IBMAuthSecretRef">IBMAuthSecretRef
@@ -2641,7 +2758,6 @@ github.com/external-secrets/external-secrets/apis/meta/v1.SecretKeySelector
 </em>
 </td>
 <td>
-<em>(Optional)</em>
 <p>The SecretAccessKey is used for authentication</p>
 </td>
 </tr>

+ 5 - 5
go.mod

@@ -35,7 +35,7 @@ replace (
 require (
 	cloud.google.com/go v0.102.0 // indirect
 	cloud.google.com/go/iam v0.3.0
-	cloud.google.com/go/secretmanager v1.4.0
+	cloud.google.com/go/secretmanager v1.5.0
 	github.com/Azure/azure-sdk-for-go v66.0.0+incompatible
 	github.com/Azure/go-autorest/autorest v0.11.27
 	github.com/Azure/go-autorest/autorest/adal v0.9.20
@@ -65,7 +65,7 @@ require (
 	github.com/huandu/xstrings v1.3.2 // indirect
 	github.com/lestrrat-go/jwx v1.2.25
 	github.com/onsi/ginkgo/v2 v2.1.4
-	github.com/onsi/gomega v1.19.0
+	github.com/onsi/gomega v1.20.0
 	github.com/oracle/oci-go-sdk/v56 v56.1.0
 	github.com/prometheus/client_golang v1.12.2
 	github.com/prometheus/client_model v0.2.0
@@ -79,7 +79,7 @@ require (
 	go.uber.org/zap v1.21.0
 	golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e
 	golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2
-	google.golang.org/api v0.87.0
+	google.golang.org/api v0.88.0
 	google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f
 	google.golang.org/grpc v1.47.0
 	gopkg.in/yaml.v3 v3.0.1
@@ -90,11 +90,11 @@ require (
 	k8s.io/client-go v0.23.5
 	k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9
 	sigs.k8s.io/controller-runtime v0.11.2
-	sigs.k8s.io/controller-tools v0.9.0
+	sigs.k8s.io/controller-tools v0.9.2
 	software.sslmate.com/src/go-pkcs12 v0.2.0
 )
 
-require github.com/1Password/connect-sdk-go v1.4.0
+require github.com/1Password/connect-sdk-go v1.5.0
 
 require (
 	github.com/argoproj/argo-cd/v2 v2.4.6

+ 18 - 15
go.sum

@@ -57,8 +57,8 @@ cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2k
 cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
 cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
 cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
-cloud.google.com/go/secretmanager v1.4.0 h1:Cl+kDYvKHjPQ1l2DZDr2FG/cXUzNGCZkh05BARgddo8=
-cloud.google.com/go/secretmanager v1.4.0/go.mod h1:h2VZz7Svt1W9/YVl7mfcX9LddvS6SOLOvMoOXBhYT1k=
+cloud.google.com/go/secretmanager v1.5.0 h1:XdbW+Fx5amsRzjHeFbDAQI2v2VUkSl3BWEgkQD6z8hY=
+cloud.google.com/go/secretmanager v1.5.0/go.mod h1:5C9kM+RwSpkURNovKySkNvGQLUaOgyoR5W0RUx2SyHQ=
 cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
 cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
 cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
@@ -70,8 +70,8 @@ code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFj
 code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/1Password/connect-sdk-go v1.4.0 h1:c1cR22z69E634ZxEhjsBI08FNEcDBuM57IKMFDk04aM=
-github.com/1Password/connect-sdk-go v1.4.0/go.mod h1:ADZd9XFWwbBcnAayv7hVm9LTF0WkyoJ37jVA6BRtqzE=
+github.com/1Password/connect-sdk-go v1.5.0 h1:F0WJcLSzGg3iXEDY49/ULdszYKsQLGTzn+2cyYXqiyk=
+github.com/1Password/connect-sdk-go v1.5.0/go.mod h1:TdynFeyvaRoackENbJ8RfJokH+WAowAu1MLmUbdMq6s=
 github.com/Azure/azure-sdk-for-go v55.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
 github.com/Azure/azure-sdk-for-go v66.0.0+incompatible h1:bmmC38SlE8/E81nNADlgmVGurPWMHDX2YNXVQMrBpEE=
 github.com/Azure/azure-sdk-for-go v66.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
@@ -114,10 +114,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
 github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
 github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
 github.com/GoogleCloudPlatform/k8s-cloud-provider v1.16.1-0.20210702024009-ea6160c1d0e3/go.mod h1:8XasY4ymP2V/tn2OOV9ZadmiTE1FIB/h3W+yNlPttKw=
-github.com/HdrHistogram/hdrhistogram-go v1.0.1 h1:GX8GAYDuhlFQnI2fRDHQhTlkHMz8bEn0jTI6LJU0mpw=
-github.com/HdrHistogram/hdrhistogram-go v1.0.1 h1:GX8GAYDuhlFQnI2fRDHQhTlkHMz8bEn0jTI6LJU0mpw=
-github.com/HdrHistogram/hdrhistogram-go v1.0.1/go.mod h1:BWJ+nMSHY3L41Zj7CA3uXnloDp7xxV0YvstAE7nKTaM=
-github.com/HdrHistogram/hdrhistogram-go v1.0.1/go.mod h1:BWJ+nMSHY3L41Zj7CA3uXnloDp7xxV0YvstAE7nKTaM=
+github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM=
+github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
 github.com/IBM/go-sdk-core/v5 v5.9.5/go.mod h1:YlOwV9LeuclmT/qi/LAK2AsobbAP42veV0j68/rlZsE=
 github.com/IBM/go-sdk-core/v5 v5.10.1 h1:IEpjDJyB7okrC6bJ7fPZqBiOv+16VichT6kZXAz9bbQ=
 github.com/IBM/go-sdk-core/v5 v5.10.1/go.mod h1:u/33BzPy8sthgEhSeBnf6/kPCqwvC9VKw5byfqQfbe0=
@@ -1120,8 +1118,9 @@ github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7
 github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
 github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
 github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
-github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
 github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
+github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q=
+github.com/onsi/gomega v1.20.0/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
 github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
@@ -1627,6 +1626,7 @@ golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su
 golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.0.0-20220621193019-9d032be2e588/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
 golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@@ -1793,10 +1793,12 @@ golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220624220833-87e55d714810 h1:rHZQSjJdAI4Xf5Qzeh2bBc5YJIkPFVM6oDtMFYmgws0=
 golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -1917,6 +1919,7 @@ gomodules.xyz/notify v0.1.0/go.mod h1:wGy0vLXGpabCg0j9WbjzXf7pM7Khz11FqCLtBbTujP
 gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
 gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0=
 gonum.org/v1/gonum v0.6.2/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU=
+gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
 gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
 gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ=
 gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
@@ -1965,8 +1968,9 @@ google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69
 google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
 google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
 google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
-google.golang.org/api v0.87.0 h1:pUQVF/F+X7Tl1lo4LJoJf5BOpjtmINU80p9XpYTU2p4=
-google.golang.org/api v0.87.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
+google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g=
+google.golang.org/api v0.88.0 h1:MPwxQRqpyskYhr2iNyfsQ8R06eeyhe7UEuR30p136ZQ=
+google.golang.org/api v0.88.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
 google.golang.org/appengine v1.0.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -2061,7 +2065,6 @@ google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2
 google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
 google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
 google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
-google.golang.org/genproto v0.0.0-20220405205423-9d709892a2bf/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
 google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
 google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
 google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
@@ -2072,6 +2075,7 @@ google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP
 google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
 google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
 google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
+google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
 google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f h1:hJ/Y5SqPXbarffmAsApliUlcvMU+wScNGfyop4bZm8o=
 google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
 google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
@@ -2185,7 +2189,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
 gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20220512140231-539c8e751b99/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
@@ -2279,8 +2282,8 @@ sigs.k8s.io/controller-runtime v0.11.0/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eM
 sigs.k8s.io/controller-runtime v0.11.2 h1:H5GTxQl0Mc9UjRJhORusqfJCIjBO8UtUxGggCwL1rLA=
 sigs.k8s.io/controller-runtime v0.11.2/go.mod h1:P6QCzrEjLaZGqHsfd+os7JQ+WFZhvB8MRFsn4dWF7O4=
 sigs.k8s.io/controller-tools v0.8.0/go.mod h1:qE2DXhVOiEq5ijmINcFbqi9GZrrUjzB1TuJU0xa6eoY=
-sigs.k8s.io/controller-tools v0.9.0 h1:b/vSEPpA8hiMiyzDfLbZdCn3hoAcy3/868OHhYtHY9w=
-sigs.k8s.io/controller-tools v0.9.0/go.mod h1:NUkn8FTV3Sad3wWpSK7dt/145qfuQ8CKJV6j4jHC5rM=
+sigs.k8s.io/controller-tools v0.9.2 h1:AkTE3QAdz9LS4iD3EJvHyYxBkg/g9fTbgiYsrcsFCcM=
+sigs.k8s.io/controller-tools v0.9.2/go.mod h1:NUkn8FTV3Sad3wWpSK7dt/145qfuQ8CKJV6j4jHC5rM=
 sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
 sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 h1:kDi4JBNAsJWfz1aEXhO8Jg87JJaPNLh5tIzYHgStQ9Y=
 sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY=

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

@@ -3,6 +3,7 @@ repo_url: https://github.com/external-secrets/external-secrets
 repo_name: External Secrets Operator
 site_dir: ../../site
 docs_dir: ../../docs
+edit_uri: ./edit/main/docs/
 remote_branch: gh-pages
 theme:
   name: material

+ 33 - 0
hack/crd.generate.sh

@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+BUNDLE_DIR="${1}"
+CRD_DIR="${2}"
+BUNDLE_YAML="${BUNDLE_DIR}/bundle.yaml"
+
+cd "${SCRIPT_DIR}"/../
+
+go run sigs.k8s.io/controller-tools/cmd/controller-gen \
+  object:headerFile="hack/boilerplate.go.txt" \
+  paths="./..."
+go run sigs.k8s.io/controller-tools/cmd/controller-gen crd \
+  paths="./..." \
+  output:crd:artifacts:config="${CRD_DIR}/bases"
+
+# Remove extra header lines in generated CRDs
+# This is needed for building the helm chart
+for f in "${CRD_DIR}"/bases/*.yaml; do
+  if [[ $f == *kustomization.yaml ]];
+  then
+      continue;
+  fi;
+  tail -n +2 < "$f" > "$f.bkp"
+  cp "$f.bkp" "$f"
+  rm "$f.bkp"
+done
+
+shopt -s extglob
+yq e \
+    '.spec.conversion.strategy = "Webhook" | .spec.conversion.webhook.conversionReviewVersions = ["v1"] | .spec.conversion.webhook.clientConfig.service.name = "kubernetes" | .spec.conversion.webhook.clientConfig.service.namespace = "default" |	.spec.conversion.webhook.clientConfig.service.path = "/convert"' \
+    "${CRD_DIR}"/bases/!(kustomization).yaml > "${BUNDLE_YAML}"

+ 33 - 0
hack/helm.generate.sh

@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+set -euo pipefail
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+BUNDLE_DIR="${1}"
+HELM_DIR="${2}"
+
+if [[ "$OSTYPE" == "darwin"* ]]; then
+  SEDPRG="gsed"
+else
+  SEDPRG="sed"
+fi
+
+cd "${SCRIPT_DIR}"/../
+
+# Split the generated bundle yaml file to inject control flags
+yq e -Ns "\"${HELM_DIR}/templates/crds/\" + .spec.names.singular" ${BUNDLE_DIR}/bundle.yaml
+
+# Add helm if statement for controlling the install of CRDs
+for i in "${HELM_DIR}"/templates/crds/*.yml; do
+  export CRDS_FLAG_NAME="create$(yq e '.spec.names.kind' $i)"
+  cp "$i" "$i.bkp"
+  if [[ "$CRDS_FLAG_NAME" == *"Cluster"* ]]; then
+    echo "{{- if and (.Values.installCRDs) (.Values.crds.$CRDS_FLAG_NAME) }}" > "$i"
+  else
+    echo "{{- if .Values.installCRDs }}" > "$i"
+  fi
+  cat "$i.bkp" >> "$i"
+  echo "{{- end }}" >> "$i"
+  rm "$i.bkp"
+  $SEDPRG -i 's/name: kubernetes/name: {{ include "external-secrets.fullname" . }}-webhook/g' "$i"
+  $SEDPRG -i 's/namespace: default/namespace: {{ .Release.Namespace | quote }}/g' "$i"
+  mv "$i" "${i%.yml}.yaml"
+done

+ 68 - 19
pkg/provider/ibm/provider.go

@@ -17,6 +17,7 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
+	"os"
 	"strconv"
 	"strings"
 	"time"
@@ -555,16 +556,29 @@ func (ibm *providerIBM) ValidateStore(store esv1beta1.GenericStore) error {
 	if ibmSpec.ServiceURL == nil {
 		return fmt.Errorf("serviceURL is required")
 	}
-	secretRef := ibmSpec.Auth.SecretRef.SecretAPIKey
-	err := utils.ValidateSecretSelector(store, secretRef)
-	if err != nil {
-		return err
-	}
-	if secretRef.Name == "" {
-		return fmt.Errorf("secretAPIKey.name cannot be empty")
-	}
-	if secretRef.Key == "" {
-		return fmt.Errorf("secretAPIKey.key cannot be empty")
+
+	containerRef := ibmSpec.Auth.ContainerAuth
+	secretKeyRef := ibmSpec.Auth.SecretRef.SecretAPIKey
+	if utils.IsNil(containerRef.Profile) || (containerRef.Profile == "") {
+		// proceed with API Key Auth validation
+		err := utils.ValidateSecretSelector(store, secretKeyRef)
+		if err != nil {
+			return err
+		}
+		if secretKeyRef.Name == "" {
+			return fmt.Errorf("secretAPIKey.name cannot be empty")
+		}
+		if secretKeyRef.Key == "" {
+			return fmt.Errorf("secretAPIKey.key cannot be empty")
+		}
+	} else {
+		// proceed with container auth
+		if containerRef.TokenLocation == "" {
+			containerRef.TokenLocation = "/var/run/secrets/tokens/vault-token"
+		}
+		if _, err := os.Open(containerRef.TokenLocation); err != nil {
+			return fmt.Errorf("cannot read container auth token %s. %w", containerRef.TokenLocation, err)
+		}
 	}
 	return nil
 }
@@ -585,16 +599,51 @@ func (ibm *providerIBM) NewClient(ctx context.Context, store esv1beta1.GenericSt
 		storeKind: store.GetObjectKind().GroupVersionKind().Kind,
 	}
 
-	if err := iStore.setAuth(ctx); err != nil {
-		return nil, err
-	}
+	var err error
+	var secretsManager *sm.SecretsManagerV1
+	containerAuthProfile := iStore.store.Auth.ContainerAuth.Profile
+	if containerAuthProfile != "" {
+		// container-based auth
+		containerAuthToken := iStore.store.Auth.ContainerAuth.TokenLocation
+		containerAuthEndpoint := iStore.store.Auth.ContainerAuth.IAMEndpoint
+
+		if containerAuthToken == "" {
+			// API default path
+			containerAuthToken = "/var/run/secrets/tokens/vault-token"
+		}
+		if containerAuthEndpoint == "" {
+			// API default path
+			containerAuthEndpoint = "https://iam.cloud.ibm.com"
+		}
 
-	secretsManager, err := sm.NewSecretsManagerV1(&sm.SecretsManagerV1Options{
-		URL: *storeSpec.Provider.IBM.ServiceURL,
-		Authenticator: &core.IamAuthenticator{
-			ApiKey: string(iStore.credentials),
-		},
-	})
+		authenticator, err := core.NewContainerAuthenticatorBuilder().
+			SetIAMProfileName(containerAuthProfile).
+			SetCRTokenFilename(containerAuthToken).
+			SetURL(containerAuthEndpoint).
+			Build()
+		if err != nil {
+			return nil, fmt.Errorf(errIBMClient, err)
+		}
+		secretsManager, err = sm.NewSecretsManagerV1(&sm.SecretsManagerV1Options{
+			URL:           *storeSpec.Provider.IBM.ServiceURL,
+			Authenticator: authenticator,
+		})
+		if err != nil {
+			return nil, fmt.Errorf(errIBMClient, err)
+		}
+	} else {
+		// API Key-based auth
+		if err := iStore.setAuth(ctx); err != nil {
+			return nil, err
+		}
+
+		secretsManager, err = sm.NewSecretsManagerV1(&sm.SecretsManagerV1Options{
+			URL: *storeSpec.Provider.IBM.ServiceURL,
+			Authenticator: &core.IamAuthenticator{
+				ApiKey: string(iStore.credentials),
+			},
+		})
+	}
 
 	// Setup retry options, but only if present
 	if storeSpec.RetrySettings != nil {

+ 13 - 0
pkg/provider/ibm/provider_test.go

@@ -134,6 +134,8 @@ func TestValidateStore(t *testing.T) {
 	}
 	url := "my-url"
 	store.Spec.Provider.IBM.ServiceURL = &url
+	var nilProfile esv1beta1.IBMAuthContainerAuth
+	store.Spec.Provider.IBM.Auth.ContainerAuth = nilProfile
 	err = p.ValidateStore(store)
 	if err == nil {
 		t.Errorf(errExpectedErr)
@@ -150,6 +152,17 @@ func TestValidateStore(t *testing.T) {
 	} else if err.Error() != "namespace not allowed with namespaced SecretStore" {
 		t.Errorf("KeySelector test failed: expected namespace not allowed, got %v", err)
 	}
+
+	// add container auth test
+	store.Spec.Provider.IBM = &esv1beta1.IBMProvider{}
+	store.Spec.Provider.IBM.ServiceURL = &url
+	store.Spec.Provider.IBM.Auth.ContainerAuth.Profile = "Trusted IAM Profile"
+	store.Spec.Provider.IBM.Auth.ContainerAuth.TokenLocation = "/a/path/to/nowhere/that/should/exist"
+	err = p.ValidateStore(store)
+	expected := "cannot read container auth token"
+	if !ErrorContains(err, expected) {
+		t.Errorf("ProfileSelector test failed: %s, expected: '%s'", err.Error(), expected)
+	}
 }
 
 // test the sm<->gcp interface

+ 21 - 4
pkg/provider/onepassword/fake/fake.go

@@ -53,8 +53,11 @@ func (mockClient *OnePasswordMockClient) GetVaultByUUID(uuid string) (*onepasswo
 	return &onepassword.Vault{}, nil
 }
 
-// GetVaultByTitle unused fake.
+// GetVaultByTitle returns a vault, you must preload, only one.
 func (mockClient *OnePasswordMockClient) GetVaultByTitle(uuid string) (*onepassword.Vault, error) {
+	if len(mockClient.MockVaults[uuid]) != 0 {
+		return &mockClient.MockVaults[uuid][0], nil
+	}
 	return &onepassword.Vault{}, nil
 }
 
@@ -82,9 +85,18 @@ func (mockClient *OnePasswordMockClient) GetItem(itemUUID, vaultUUID string) (*o
 	return &onepassword.Item{}, errors.New("status 400: Invalid Item UUID")
 }
 
-// GetItemByUUID unused fake.
-func (mockClient *OnePasswordMockClient) GetItemByUUID(uuid, vaultQuery string) (*onepassword.Item, error) {
-	return &onepassword.Item{}, nil
+// GetItemByUUID returns a *onepassword.Item, you must preload.
+func (mockClient *OnePasswordMockClient) GetItemByUUID(itemUUID, vaultUUID string) (*onepassword.Item, error) {
+	for _, item := range mockClient.MockItems[vaultUUID] {
+		if item.ID == itemUUID {
+			// load the fields that GetItemsByTitle does not
+			item.Fields = mockClient.MockItemFields[vaultUUID][itemUUID]
+
+			return &item, nil
+		}
+	}
+
+	return &onepassword.Item{}, errors.New("status 400: Invalid Item UUID")
 }
 
 // GetItemByTitle unused fake.
@@ -124,6 +136,11 @@ func (mockClient *OnePasswordMockClient) DeleteItemByID(itemUUID, vaultQuery str
 	return nil
 }
 
+// DeleteItemByTitle unused fake.
+func (mockClient *OnePasswordMockClient) DeleteItemByTitle(title, vaultQuery string) error {
+	return nil
+}
+
 // GetFiles unused fake.
 func (mockClient *OnePasswordMockClient) GetFiles(itemQuery, vaultQuery string) ([]onepassword.File, error) {
 	return []onepassword.File{}, nil

+ 7 - 14
pkg/provider/onepassword/onepassword.go

@@ -45,7 +45,6 @@ const (
 	errFetchK8sSecret                             = "could not fetch ConnectToken Secret: %w"
 	errMissingToken                               = "missing Secret Token"
 	errGetVault                                   = "error finding 1Password Vault: %w"
-	errExpectedOneVault                           = "expected one 1Password Vault matching %w"
 	errExpectedOneItem                            = "expected one 1Password Item matching %w"
 	errGetItem                                    = "error finding 1Password Item: %w"
 	errKeyNotFound                                = "key not found in 1Password Vaults: %w"
@@ -183,7 +182,7 @@ func (provider *ProviderOnePassword) GetSecret(ctx context.Context, ref esv1beta
 // to be able to retrieve secrets from the provider.
 func (provider *ProviderOnePassword) Validate() (esv1beta1.ValidationResult, error) {
 	for vaultName := range provider.vaults {
-		_, err := provider.client.GetItems(vaultName)
+		_, err := provider.client.GetVaultByTitle(vaultName)
 		if err != nil {
 			return esv1beta1.ValidationResultError, err
 		}
@@ -221,15 +220,12 @@ func (provider *ProviderOnePassword) GetAllSecrets(ctx context.Context, ref esv1
 	secretData := make(map[string][]byte)
 	sortedVaults := sortVaults(provider.vaults)
 	for _, vaultName := range sortedVaults {
-		vaults, err := provider.client.GetVaultsByTitle(vaultName)
+		vault, err := provider.client.GetVaultByTitle(vaultName)
 		if err != nil {
 			return nil, fmt.Errorf(errGetVault, err)
 		}
-		if len(vaults) != 1 {
-			return nil, fmt.Errorf(errExpectedOneVault, fmt.Errorf(incorrectCountFormat, vaultName, len(vaults)))
-		}
 
-		err = provider.getAllForVault(vaults[0].ID, ref, secretData)
+		err = provider.getAllForVault(vault.ID, ref, secretData)
 		if err != nil {
 			return nil, err
 		}
@@ -246,22 +242,19 @@ func (provider *ProviderOnePassword) Close(ctx context.Context) error {
 func (provider *ProviderOnePassword) findItem(name string) (*onepassword.Item, error) {
 	sortedVaults := sortVaults(provider.vaults)
 	for _, vaultName := range sortedVaults {
-		vaults, err := provider.client.GetVaultsByTitle(vaultName)
+		vault, err := provider.client.GetVaultByTitle(vaultName)
 		if err != nil {
 			return nil, fmt.Errorf(errGetVault, err)
 		}
-		if len(vaults) != 1 {
-			return nil, fmt.Errorf(errExpectedOneVault, fmt.Errorf(incorrectCountFormat, vaultName, len(vaults)))
-		}
 
 		// use GetItemsByTitle instead of GetItemByTitle in order to handle length cases
-		items, err := provider.client.GetItemsByTitle(name, vaults[0].ID)
+		items, err := provider.client.GetItemsByTitle(name, vault.ID)
 		if err != nil {
 			return nil, fmt.Errorf(errGetItem, err)
 		}
 		switch {
 		case len(items) == 1:
-			return provider.client.GetItem(items[0].ID, items[0].Vault.ID)
+			return provider.client.GetItemByUUID(items[0].ID, items[0].Vault.ID)
 		case len(items) > 1:
 			return nil, fmt.Errorf(errExpectedOneItem, fmt.Errorf(incorrectCountFormat, name, len(items)))
 		}
@@ -311,7 +304,7 @@ func (provider *ProviderOnePassword) getFields(item *onepassword.Item, property
 }
 
 func (provider *ProviderOnePassword) getAllFields(item onepassword.Item, ref esv1beta1.ExternalSecretFind, secretData map[string][]byte) error {
-	i, err := provider.client.GetItem(item.ID, item.Vault.ID)
+	i, err := provider.client.GetItemByUUID(item.ID, item.Vault.ID)
 	if err != nil {
 		return fmt.Errorf(errGetItem, err)
 	}

+ 1 - 1
pkg/provider/onepassword/onepassword_test.go

@@ -172,7 +172,7 @@ func TestFindItem(t *testing.T) {
 				{
 					checkNote:    "two vaults",
 					findItemName: myItem,
-					expectedErr:  fmt.Errorf(errExpectedOneVault, fmt.Errorf("'my-vault', got 2")),
+					expectedErr:  fmt.Errorf("key not found in 1Password Vaults: my-item in: map[my-shared-vault:2 my-vault:1]"),
 				},
 			},
 		},

+ 3 - 0
pkg/utils/utils.go

@@ -69,6 +69,9 @@ func Decode(strategy esv1beta1.ExternalSecretDecodingStrategy, in []byte) ([]byt
 		return out, nil
 	case esv1beta1.ExternalSecretDecodeNone:
 		return in, nil
+	// default when stored version is v1alpha1
+	case "":
+		return in, nil
 	case esv1beta1.ExternalSecretDecodeAuto:
 		out, err := Decode(esv1beta1.ExternalSecretDecodeBase64, in)
 		if err != nil {