Просмотр исходного кода

Merge branch 'beach-team' of https://github.com/external-secrets/external-secrets into HEAD

git 4 лет назад
Родитель
Сommit
9598fd21d4
29 измененных файлов с 903 добавлено и 4 удалено
  1. 123 0
      apis/externalsecrets/v1alpha1/secretsink_types.go
  2. 229 0
      apis/externalsecrets/v1alpha1/zz_generated.deepcopy.go
  3. 5 0
      apis/externalsecrets/v1beta1/provider.go
  4. 9 0
      apis/externalsecrets/v1beta1/provider_schema_test.go
  5. 14 0
      apis/externalsecrets/v1beta1/secretstore_types.go
  6. 10 0
      config/crds/bases/external-secrets.io_clustersecretstores.yaml
  7. 145 0
      config/crds/bases/external-secrets.io_secretsinks.yaml
  8. 7 0
      config/crds/bases/external-secrets.io_secretstores.yaml
  9. 162 0
      deploy/crds/bundle.yaml
  10. 9 0
      pkg/controllers/secretstore/common.go
  11. 33 0
      pkg/controllers/secretstore/common_test.go
  12. 9 0
      pkg/provider/akeyless/akeyless.go
  13. 9 0
      pkg/provider/alibaba/kms.go
  14. 6 1
      pkg/provider/aws/parameterstore/parameterstore.go
  15. 5 0
      pkg/provider/aws/provider.go
  16. 5 0
      pkg/provider/aws/secretsmanager/secretsmanager.go
  17. 10 0
      pkg/provider/azure/keyvault/keyvault.go
  18. 10 0
      pkg/provider/fake/fake.go
  19. 10 0
      pkg/provider/gcp/secretmanager/secretsmanager.go
  20. 10 0
      pkg/provider/gitlab/gitlab.go
  21. 10 0
      pkg/provider/ibm/provider.go
  22. 10 0
      pkg/provider/kubernetes/kubernetes.go
  23. 10 0
      pkg/provider/oracle/oracle.go
  24. 5 0
      pkg/provider/senhasegura/dsm/dsm.go
  25. 5 0
      pkg/provider/senhasegura/provider.go
  26. 11 0
      pkg/provider/testing/fake/fake.go
  27. 12 3
      pkg/provider/vault/vault.go
  28. 10 0
      pkg/provider/webhook/webhook.go
  29. 10 0
      pkg/provider/yandex/lockbox/lockbox.go

+ 123 - 0
apis/externalsecrets/v1alpha1/secretsink_types.go

@@ -0,0 +1,123 @@
+/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import (
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+type SecretSinkStoreRef struct {
+	// Name of the SecretStore resource
+	Name string `json:"name"`
+
+	// Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
+	// Defaults to `SecretStore`
+	// +optional
+	Kind string `json:"kind,omitempty"`
+}
+
+// SecretSinkSpec configures the behavior of the SecretSink.
+type SecretSinkSpec struct {
+	SecretStoreRefs []SecretSinkStoreRef `json:"secretStoreRefs"`
+	Selector        SecretSinkSelector   `json:"selector"`
+	Data            []SecretSinkData     `json:"data,omitempty"`
+}
+
+type SecretSinkSecret struct {
+	Name string `json:"name"`
+}
+
+type SecretSinkSelector struct {
+	Secret SecretSinkSecret `json:"secret"`
+}
+
+type SecretSinkRemoteRefs struct {
+	RemoteKey string `json:"remoteKey"`
+}
+
+type SecretSinkMatch struct {
+	SecretKey  string                 `json:"secretKey"`
+	RemoteRefs []SecretSinkRemoteRefs `json:"remoteRefs"`
+}
+
+type SecretSinkData struct {
+	Match []SecretSinkMatch `json:"match"`
+}
+
+// SecretSinkConditionType indicates the condition of the SecretSink.
+type SecretSinkConditionType string
+
+const (
+	SecretSinkSynced         SecretSinkConditionType = "Synced"
+	SecretSinkNotSynced      SecretSinkConditionType = "NotSynced"
+	SecretSinkError          SecretSinkConditionType = "Error"
+	SecretSinkNotImplemented SecretSinkConditionType = "NotImplemented"
+)
+
+// SecretSinkStatusCondition indicates the status of the SecretSink.
+type SecretSinkStatusCondition struct {
+	Type   SecretSinkConditionType `json:"type"`
+	Status corev1.ConditionStatus  `json:"status"`
+
+	// +optional
+	Reason string `json:"reason,omitempty"`
+
+	// +optional
+	Message string `json:"message,omitempty"`
+
+	// +optional
+	LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
+}
+
+// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].reason`
+// SecretSinkStatus indicates the history of the status of SecretSink.
+type SecretSinkStatus struct {
+	// +nullable
+	// refreshTime is the time and date the external secret was fetched and
+	// the target secret updated
+	RefreshTime metav1.Time `json:"refreshTime,omitempty"`
+
+	// SyncedResourceVersion keeps track of the last synced version.
+	SyncedResourceVersion string `json:"syncedResourceVersion,omitempty"`
+
+	// +optional
+	Conditions []SecretSinkStatusCondition `json:"conditions,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+// +kubebuilder:storageversion
+// Secretsinks is the Schema for the secretsinks API.
+// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].reason`
+// +kubebuilder:subresource:status
+// +kubebuilder:resource:scope=Namespaced,categories={secretsinks}
+
+type SecretSink struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec   SecretSinkSpec   `json:"spec,omitempty"`
+	Status SecretSinkStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].reason`
+// SecretSinkList contains a list of SecretSink resources.
+type SecretSinkList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []SecretSink `json:"items"`
+}

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

@@ -964,6 +964,235 @@ func (in *OracleSecretRef) DeepCopy() *OracleSecretRef {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSink) DeepCopyInto(out *SecretSink) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Spec.DeepCopyInto(&out.Spec)
+	in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSink.
+func (in *SecretSink) DeepCopy() *SecretSink {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSink)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *SecretSink) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkData) DeepCopyInto(out *SecretSinkData) {
+	*out = *in
+	if in.Match != nil {
+		in, out := &in.Match, &out.Match
+		*out = make([]SecretSinkMatch, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkData.
+func (in *SecretSinkData) DeepCopy() *SecretSinkData {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkData)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkList) DeepCopyInto(out *SecretSinkList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]SecretSink, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkList.
+func (in *SecretSinkList) DeepCopy() *SecretSinkList {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *SecretSinkList) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkMatch) DeepCopyInto(out *SecretSinkMatch) {
+	*out = *in
+	if in.RemoteRefs != nil {
+		in, out := &in.RemoteRefs, &out.RemoteRefs
+		*out = make([]SecretSinkRemoteRefs, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkMatch.
+func (in *SecretSinkMatch) DeepCopy() *SecretSinkMatch {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkMatch)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkRemoteRefs) DeepCopyInto(out *SecretSinkRemoteRefs) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkRemoteRefs.
+func (in *SecretSinkRemoteRefs) DeepCopy() *SecretSinkRemoteRefs {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkRemoteRefs)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkSecret) DeepCopyInto(out *SecretSinkSecret) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkSecret.
+func (in *SecretSinkSecret) DeepCopy() *SecretSinkSecret {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkSecret)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkSelector) DeepCopyInto(out *SecretSinkSelector) {
+	*out = *in
+	out.Secret = in.Secret
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkSelector.
+func (in *SecretSinkSelector) DeepCopy() *SecretSinkSelector {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkSelector)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkSpec) DeepCopyInto(out *SecretSinkSpec) {
+	*out = *in
+	if in.SecretStoreRefs != nil {
+		in, out := &in.SecretStoreRefs, &out.SecretStoreRefs
+		*out = make([]SecretSinkStoreRef, len(*in))
+		copy(*out, *in)
+	}
+	out.Selector = in.Selector
+	if in.Data != nil {
+		in, out := &in.Data, &out.Data
+		*out = make([]SecretSinkData, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkSpec.
+func (in *SecretSinkSpec) DeepCopy() *SecretSinkSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkStatus) DeepCopyInto(out *SecretSinkStatus) {
+	*out = *in
+	in.RefreshTime.DeepCopyInto(&out.RefreshTime)
+	if in.Conditions != nil {
+		in, out := &in.Conditions, &out.Conditions
+		*out = make([]SecretSinkStatusCondition, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkStatus.
+func (in *SecretSinkStatus) DeepCopy() *SecretSinkStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkStatusCondition) DeepCopyInto(out *SecretSinkStatusCondition) {
+	*out = *in
+	in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkStatusCondition.
+func (in *SecretSinkStatusCondition) DeepCopy() *SecretSinkStatusCondition {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkStatusCondition)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretSinkStoreRef) DeepCopyInto(out *SecretSinkStoreRef) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSinkStoreRef.
+func (in *SecretSinkStoreRef) DeepCopy() *SecretSinkStoreRef {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretSinkStoreRef)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *SecretStore) DeepCopyInto(out *SecretStore) {
 	*out = *in

+ 5 - 0
apis/externalsecrets/v1beta1/provider.go

@@ -44,6 +44,8 @@ type Provider interface {
 
 	// ValidateStore checks if the provided store is valid
 	ValidateStore(store GenericStore) error
+	// Capabilities returns the provider Capabilities (Read, Write, ReadWrite)
+	Capabilities() SecretStoreCapabilities
 }
 
 // +kubebuilder:object:root=false
@@ -58,6 +60,9 @@ type SecretsClient interface {
 	// then the secret entry will be deleted depending on the deletionPolicy.
 	GetSecret(ctx context.Context, ref ExternalSecretDataRemoteRef) ([]byte, error)
 
+	// SetSecret willl write a single secret into the provider
+	SetSecret() error
+
 	// Validate checks if the client is configured correctly
 	// and is able to retrieve secrets from the provider.
 	// If the validation result is unknown it will be ignored.

+ 9 - 0
apis/externalsecrets/v1beta1/provider_schema_test.go

@@ -25,11 +25,20 @@ type PP struct{}
 
 const shouldBeRegistered = "provider should be registered"
 
+func (p *PP) Capabilities() SecretStoreCapabilities {
+	return SecretStoreReadOnly
+}
+
 // New constructs a SecretsManager Provider.
 func (p *PP) NewClient(ctx context.Context, store GenericStore, kube client.Client, namespace string) (SecretsClient, error) {
 	return p, nil
 }
 
+// SetSecret writes a single secret into a provider.
+func (p *PP) SetSecret() error {
+	return nil
+}
+
 // GetSecret returns a single secret from the provider.
 func (p *PP) GetSecret(ctx context.Context, ref ExternalSecretDataRemoteRef) ([]byte, error) {
 	return []byte("NOOP"), nil

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

@@ -133,10 +133,21 @@ type SecretStoreStatusCondition struct {
 	LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
 }
 
+// SecretStoreCapabilities defines the possible operations a SecretStore can do.
+type SecretStoreCapabilities string
+
+const (
+	SecretStoreReadOnly  SecretStoreCapabilities = "ReadOnly"
+	SecretStoreWriteOnly SecretStoreCapabilities = "WriteOnly"
+	SecretStoreReadWrite SecretStoreCapabilities = "ReadWrite"
+)
+
 // SecretStoreStatus defines the observed state of the SecretStore.
 type SecretStoreStatus struct {
 	// +optional
 	Conditions []SecretStoreStatusCondition `json:"conditions"`
+	// +optional
+	Capabilities SecretStoreCapabilities `json:"capabilities"`
 }
 
 // +kubebuilder:object:root=true
@@ -145,6 +156,7 @@ type SecretStoreStatus struct {
 // SecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields.
 // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp"
 // +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].reason`
+// +kubebuilder:printcolumn:name="Capabilities",type=string,JSONPath=`.status.capabilities`
 // +kubebuilder:subresource:status
 // +kubebuilder:resource:scope=Namespaced,categories={externalsecrets},shortName=ss
 type SecretStore struct {
@@ -169,6 +181,8 @@ type SecretStoreList struct {
 
 // ClusterSecretStore represents a secure external location for storing secrets, which can be referenced as part of `storeRef` fields.
 // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp"
+// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].reason`
+// +kubebuilder:printcolumn:name="Capabilities",type=string,JSONPath=`.status.capabilities`
 // +kubebuilder:subresource:status
 // +kubebuilder:resource:scope=Cluster,categories={externalsecrets},shortName=css
 type ClusterSecretStore struct {

+ 10 - 0
config/crds/bases/external-secrets.io_clustersecretstores.yaml

@@ -1387,6 +1387,12 @@ spec:
     - jsonPath: .metadata.creationTimestamp
       name: AGE
       type: date
+    - jsonPath: .status.conditions[?(@.type=="Ready")].reason
+      name: Status
+      type: string
+    - jsonPath: .status.capabilities
+      name: Capabilities
+      type: string
     name: v1beta1
     schema:
       openAPIV3Schema:
@@ -2827,6 +2833,10 @@ spec:
           status:
             description: SecretStoreStatus defines the observed state of the SecretStore.
             properties:
+              capabilities:
+                description: SecretStoreCapabilities defines the possible operations
+                  a SecretStore can do.
+                type: string
               conditions:
                 items:
                   properties:

+ 145 - 0
config/crds/bases/external-secrets.io_secretsinks.yaml

@@ -0,0 +1,145 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.8.0
+  creationTimestamp: null
+  name: secretsinks.external-secrets.io
+spec:
+  group: external-secrets.io
+  names:
+    categories:
+    - secretsinks
+    kind: SecretSink
+    listKind: SecretSinkList
+    plural: secretsinks
+    singular: secretsink
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .status.conditions[?(@.type=="Ready")].reason
+      name: Status
+      type: string
+    name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: SecretSinkSpec configures the behavior of the SecretSink.
+            properties:
+              data:
+                items:
+                  properties:
+                    match:
+                      items:
+                        properties:
+                          remoteRefs:
+                            items:
+                              properties:
+                                remoteKey:
+                                  type: string
+                              required:
+                              - remoteKey
+                              type: object
+                            type: array
+                          secretKey:
+                            type: string
+                        required:
+                        - remoteRefs
+                        - secretKey
+                        type: object
+                      type: array
+                  required:
+                  - match
+                  type: object
+                type: array
+              secretStoreRefs:
+                items:
+                  properties:
+                    kind:
+                      description: Kind of the SecretStore resource (SecretStore or
+                        ClusterSecretStore) Defaults to `SecretStore`
+                      type: string
+                    name:
+                      description: Name of the SecretStore resource
+                      type: string
+                  required:
+                  - name
+                  type: object
+                type: array
+              selector:
+                properties:
+                  secret:
+                    properties:
+                      name:
+                        type: string
+                    required:
+                    - name
+                    type: object
+                required:
+                - secret
+                type: object
+            required:
+            - secretStoreRefs
+            - selector
+            type: object
+          status:
+            description: SecretSinkStatus indicates the history of the status of SecretSink.
+            properties:
+              conditions:
+                items:
+                  description: SecretSinkStatusCondition indicates the status of the
+                    SecretSink.
+                  properties:
+                    lastTransitionTime:
+                      format: date-time
+                      type: string
+                    message:
+                      type: string
+                    reason:
+                      type: string
+                    status:
+                      type: string
+                    type:
+                      description: SecretSinkConditionType indicates the condition
+                        of the SecretSink.
+                      type: string
+                  required:
+                  - status
+                  - type
+                  type: object
+                type: array
+              refreshTime:
+                description: refreshTime is the time and date the external secret
+                  was fetched and the target secret updated
+                format: date-time
+                nullable: true
+                type: string
+              syncedResourceVersion:
+                description: SyncedResourceVersion keeps track of the last synced
+                  version.
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+status:
+  acceptedNames:
+    kind: ""
+    plural: ""
+  conditions: []
+  storedVersions: []

+ 7 - 0
config/crds/bases/external-secrets.io_secretstores.yaml

@@ -1390,6 +1390,9 @@ spec:
     - jsonPath: .status.conditions[?(@.type=="Ready")].reason
       name: Status
       type: string
+    - jsonPath: .status.capabilities
+      name: Capabilities
+      type: string
     name: v1beta1
     schema:
       openAPIV3Schema:
@@ -2830,6 +2833,10 @@ spec:
           status:
             description: SecretStoreStatus defines the observed state of the SecretStore.
             properties:
+              capabilities:
+                description: SecretStoreCapabilities defines the possible operations
+                  a SecretStore can do.
+                type: string
               conditions:
                 items:
                   properties:

+ 162 - 0
deploy/crds/bundle.yaml

@@ -1358,6 +1358,12 @@ spec:
         - jsonPath: .metadata.creationTimestamp
           name: AGE
           type: date
+        - jsonPath: .status.conditions[?(@.type=="Ready")].reason
+          name: Status
+          type: string
+        - jsonPath: .status.capabilities
+          name: Capabilities
+          type: string
       name: v1beta1
       schema:
         openAPIV3Schema:
@@ -2413,6 +2419,9 @@ spec:
             status:
               description: SecretStoreStatus defines the observed state of the SecretStore.
               properties:
+                capabilities:
+                  description: SecretStoreCapabilities defines the possible operations a SecretStore can do.
+                  type: string
                 conditions:
                   items:
                     properties:
@@ -2964,6 +2973,153 @@ status:
 ---
 apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.8.0
+  creationTimestamp: null
+  name: secretsinks.external-secrets.io
+spec:
+  group: external-secrets.io
+  names:
+    categories:
+      - secretsinks
+    kind: SecretSink
+    listKind: SecretSinkList
+    plural: secretsinks
+    singular: secretsink
+  scope: Namespaced
+  versions:
+    - additionalPrinterColumns:
+        - jsonPath: .status.conditions[?(@.type=="Ready")].reason
+          name: Status
+          type: string
+      name: v1alpha1
+      schema:
+        openAPIV3Schema:
+          properties:
+            apiVersion:
+              description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+              type: string
+            kind:
+              description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+              type: string
+            metadata:
+              type: object
+            spec:
+              description: SecretSinkSpec configures the behavior of the SecretSink.
+              properties:
+                data:
+                  items:
+                    properties:
+                      match:
+                        items:
+                          properties:
+                            remoteRefs:
+                              items:
+                                properties:
+                                  remoteKey:
+                                    type: string
+                                required:
+                                  - remoteKey
+                                type: object
+                              type: array
+                            secretKey:
+                              type: string
+                          required:
+                            - remoteRefs
+                            - secretKey
+                          type: object
+                        type: array
+                    required:
+                      - match
+                    type: object
+                  type: array
+                secretStoreRefs:
+                  items:
+                    properties:
+                      kind:
+                        description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore) Defaults to `SecretStore`
+                        type: string
+                      name:
+                        description: Name of the SecretStore resource
+                        type: string
+                    required:
+                      - name
+                    type: object
+                  type: array
+                selector:
+                  properties:
+                    secret:
+                      properties:
+                        name:
+                          type: string
+                      required:
+                        - name
+                      type: object
+                  required:
+                    - secret
+                  type: object
+              required:
+                - secretStoreRefs
+                - selector
+              type: object
+            status:
+              description: SecretSinkStatus indicates the history of the status of SecretSink.
+              properties:
+                conditions:
+                  items:
+                    description: SecretSinkStatusCondition indicates the status of the SecretSink.
+                    properties:
+                      lastTransitionTime:
+                        format: date-time
+                        type: string
+                      message:
+                        type: string
+                      reason:
+                        type: string
+                      status:
+                        type: string
+                      type:
+                        description: SecretSinkConditionType indicates the condition of the SecretSink.
+                        type: string
+                    required:
+                      - status
+                      - type
+                    type: object
+                  type: array
+                refreshTime:
+                  description: refreshTime is the time and date the external secret was fetched and the target secret updated
+                  format: date-time
+                  nullable: true
+                  type: string
+                syncedResourceVersion:
+                  description: SyncedResourceVersion keeps track of the last synced version.
+                  type: string
+              type: object
+          type: object
+      served: true
+      storage: true
+      subresources:
+        status: {}
+  conversion:
+    strategy: Webhook
+    webhook:
+      conversionReviewVersions:
+        - v1
+      clientConfig:
+        service:
+          name: kubernetes
+          namespace: default
+          path: /convert
+status:
+  acceptedNames:
+    kind: ""
+    plural: ""
+  conditions: []
+  storedVersions: []
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
 metadata:
   annotations:
     controller-gen.kubebuilder.io/version: v0.8.0
@@ -3993,6 +4149,9 @@ spec:
         - jsonPath: .status.conditions[?(@.type=="Ready")].reason
           name: Status
           type: string
+        - jsonPath: .status.capabilities
+          name: Capabilities
+          type: string
       name: v1beta1
       schema:
         openAPIV3Schema:
@@ -5048,6 +5207,9 @@ spec:
             status:
               description: SecretStoreStatus defines the observed state of the SecretStore.
               properties:
+                capabilities:
+                  description: SecretStoreCapabilities defines the possible operations a SecretStore can do.
+                  type: string
                 conditions:
                   items:
                     properties:

+ 9 - 0
pkg/controllers/secretstore/common.go

@@ -66,6 +66,15 @@ func reconcile(ctx context.Context, req ctrl.Request, ss esapi.GenericStore, cl
 	if err != nil {
 		return ctrl.Result{}, err
 	}
+	storeProvider, err := esapi.GetProvider(ss)
+	if err != nil {
+		return ctrl.Result{}, err
+	}
+	capStatus := esapi.SecretStoreStatus{
+		Capabilities: storeProvider.Capabilities(),
+		Conditions:   ss.GetStatus().Conditions,
+	}
+	ss.SetStatus(capStatus)
 
 	recorder.Event(ss, v1.EventTypeNormal, esapi.ReasonStoreValid, msgStoreValidated)
 	cond := NewSecretStoreCondition(esapi.SecretStoreReady, v1.ConditionTrue, esapi.ReasonStoreValid, msgStoreValidated)

+ 33 - 0
pkg/controllers/secretstore/common_test.go

@@ -125,6 +125,37 @@ var _ = Describe("SecretStore reconcile", func() {
 
 	}
 
+	readOnly := func(tc *testCase) {
+		spc := tc.store.GetSpec()
+		spc.Provider.Vault = nil
+		spc.Provider.Fake = &esapi.FakeProvider{
+			Data: []esapi.FakeProviderData{},
+		}
+
+		tc.assert = func() {
+			Eventually(func() bool {
+				ss := tc.store.Copy()
+				err := k8sClient.Get(context.Background(), types.NamespacedName{
+					Name:      defaultStoreName,
+					Namespace: ss.GetNamespace(),
+				}, ss)
+				if err != nil {
+					return false
+				}
+
+				if ss.GetStatus().Capabilities != esapi.SecretStoreReadOnly {
+					return false
+				}
+
+				return true
+			}).
+				WithTimeout(time.Second * 10).
+				WithPolling(time.Second).
+				Should(BeTrue())
+		}
+
+	}
+
 	DescribeTable("Controller Reconcile logic", func(muts ...func(tc *testCase)) {
 		for _, mut := range muts {
 			mut(test)
@@ -137,11 +168,13 @@ var _ = Describe("SecretStore reconcile", func() {
 		Entry("[namespace] invalid provider with secretStore should set InvalidStore condition", invalidProvider),
 		Entry("[namespace] ignore stores with non-matching class", ignoreControllerClass),
 		Entry("[namespace] valid provider has status=ready", validProvider),
+		Entry("[namespace] valid provider has capabilities=ReadOnly", readOnly),
 
 		// cluster store
 		Entry("[cluster] invalid provider with secretStore should set InvalidStore condition", invalidProvider, useClusterStore),
 		Entry("[cluster] ignore stores with non-matching class", ignoreControllerClass, useClusterStore),
 		Entry("[cluster] valid provider has status=ready", validProvider, useClusterStore),
+		Entry("[cluster] valid provider has capabilities=ReadOnly", validProvider, useClusterStore),
 	)
 
 })

+ 9 - 0
pkg/provider/akeyless/akeyless.go

@@ -66,6 +66,11 @@ func init() {
 	})
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (p *Provider) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient constructs a new secrets client based on the provided store.
 func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube client.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	return newClient(ctx, store, kube, namespace)
@@ -165,6 +170,10 @@ func (a *Akeyless) Validate() (esv1beta1.ValidationResult, error) {
 	return esv1beta1.ValidationResultReady, nil
 }
 
+func (a *Akeyless) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // Implements store.Client.GetSecret Interface.
 // Retrieves a secret with the secret name defined in ref.Name.
 func (a *Akeyless) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {

+ 9 - 0
pkg/provider/alibaba/kms.go

@@ -114,6 +114,10 @@ func (c *Client) setAuth(ctx context.Context) error {
 	return nil
 }
 
+func (kms *KeyManagementService) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // Empty GetAllSecrets.
 func (kms *KeyManagementService) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented
@@ -168,6 +172,11 @@ func (kms *KeyManagementService) GetSecretMap(ctx context.Context, ref esv1beta1
 	return secretData, nil
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (kms *KeyManagementService) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient constructs a new secrets client based on the provided store.
 func (kms *KeyManagementService) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	storeSpec := store.GetSpec()

+ 6 - 1
pkg/provider/aws/parameterstore/parameterstore.go

@@ -60,7 +60,12 @@ func New(sess *session.Session) (*ParameterStore, error) {
 	}, nil
 }
 
-// Empty GetAllSecrets.
+// Not Implemented SetSecret.
+func (pm *ParameterStore) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
+// GetAllSecrets fetches information from multiple secrets into a single kubernetes secret.
 func (pm *ParameterStore) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	if ref.Name != nil {
 		return pm.findByName(ref)

+ 5 - 0
pkg/provider/aws/provider.go

@@ -41,6 +41,11 @@ const (
 	errRegionNotFound         = "region not found: %s"
 )
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (p *Provider) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient constructs a new secrets client based on the provided store.
 func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube client.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	return newClient(ctx, store, kube, namespace, awsauth.DefaultSTSProvider)

+ 5 - 0
pkg/provider/aws/secretsmanager/secretsmanager.go

@@ -104,6 +104,11 @@ func (sm *SecretsManager) fetch(_ context.Context, ref esv1beta1.ExternalSecretD
 	return secretOut, nil
 }
 
+// Not Implemented SetSecret.
+func (sm *SecretsManager) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // GetAllSecrets syncs multiple secrets from aws provider into a single Kubernetes Secret.
 func (sm *SecretsManager) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	if ref.Name != nil {

+ 10 - 0
pkg/provider/azure/keyvault/keyvault.go

@@ -106,6 +106,11 @@ func init() {
 	})
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (a *Azure) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient constructs a new secrets client based on the provided store.
 func (a *Azure) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube client.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	return newClient(ctx, store, kube, namespace)
@@ -195,6 +200,11 @@ func (a *Azure) ValidateStore(store esv1beta1.GenericStore) error {
 	return nil
 }
 
+// Not Implemented SetSecret.
+func (a *Azure) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // Implements store.Client.GetAllSecrets Interface.
 // Retrieves a map[string][]byte with the secret names as key and the secret itself as the calue.
 func (a *Azure) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {

+ 10 - 0
pkg/provider/fake/fake.go

@@ -34,6 +34,11 @@ type Provider struct {
 	config *esv1beta1.FakeProvider
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (p *Provider) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube client.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	cfg, err := getProvider(store)
 	if err != nil {
@@ -55,6 +60,11 @@ func getProvider(store esv1beta1.GenericStore) (*esv1beta1.FakeProvider, error)
 	return spc.Provider.Fake, nil
 }
 
+// Not Implemented SetSecret.
+func (p *Provider) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // Empty GetAllSecrets.
 func (p *Provider) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented

+ 10 - 0
pkg/provider/gcp/secretmanager/secretsmanager.go

@@ -160,6 +160,11 @@ func serviceAccountTokenSource(ctx context.Context, store esv1beta1.GenericStore
 	return config.TokenSource(ctx), nil
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (sm *ProviderGCP) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient constructs a GCP Provider.
 func (sm *ProviderGCP) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	storeSpec := store.GetSpec()
@@ -214,6 +219,11 @@ func (sm *ProviderGCP) NewClient(ctx context.Context, store esv1beta1.GenericSto
 	return sm, nil
 }
 
+// Not Implemented SetSecret.
+func (sm *ProviderGCP) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // GetAllSecrets syncs multiple secrets from gcp provider into a single Kubernetes Secret.
 func (sm *ProviderGCP) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	if ref.Name != nil {

+ 10 - 0
pkg/provider/gitlab/gitlab.go

@@ -114,6 +114,11 @@ func NewGitlabProvider() *Gitlab {
 	return &Gitlab{}
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (g *Gitlab) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // Method on Gitlab Provider to set up client with credentials and populate projectID.
 func (g *Gitlab) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	storeSpec := store.GetSpec()
@@ -156,6 +161,11 @@ func (g *Gitlab) NewClient(ctx context.Context, store esv1beta1.GenericStore, ku
 	return g, nil
 }
 
+// Not Implemented SetSecret.
+func (g *Gitlab) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // Empty GetAllSecrets.
 func (g *Gitlab) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented

+ 10 - 0
pkg/provider/ibm/provider.go

@@ -100,6 +100,11 @@ func (c *client) setAuth(ctx context.Context) error {
 	return nil
 }
 
+// Not Implemented SetSecret.
+func (ibm *providerIBM) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // Empty GetAllSecrets.
 func (ibm *providerIBM) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented
@@ -520,6 +525,11 @@ func (ibm *providerIBM) ValidateStore(store esv1beta1.GenericStore) error {
 	return nil
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (ibm *providerIBM) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 func (ibm *providerIBM) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	storeSpec := store.GetSpec()
 	ibmSpec := storeSpec.Provider.IBM

+ 10 - 0
pkg/provider/kubernetes/kubernetes.go

@@ -79,6 +79,11 @@ func init() {
 	})
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (k *ProviderKubernetes) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient constructs a Kubernetes Provider.
 func (k *ProviderKubernetes) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	storeSpec := store.GetSpec()
@@ -125,6 +130,11 @@ func (k *ProviderKubernetes) Close(ctx context.Context) error {
 	return nil
 }
 
+// Not Implemented SetSecret.
+func (k *ProviderKubernetes) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 func (k *ProviderKubernetes) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
 	if ref.Property == "" {
 		return nil, fmt.Errorf(errPropertyNotFound)

+ 10 - 0
pkg/provider/oracle/oracle.go

@@ -65,6 +65,11 @@ type VMInterface interface {
 	GetSecretBundleByName(ctx context.Context, request secrets.GetSecretBundleByNameRequest) (secrets.GetSecretBundleByNameResponse, error)
 }
 
+// Not Implemented SetSecret.
+func (vms *VaultManagementService) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // Empty GetAllSecrets.
 func (vms *VaultManagementService) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented
@@ -125,6 +130,11 @@ func (vms *VaultManagementService) GetSecretMap(ctx context.Context, ref esv1bet
 	return secretData, nil
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (vms *VaultManagementService) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient constructs a new secrets client based on the provided store.
 func (vms *VaultManagementService) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	storeSpec := store.GetSpec()

+ 5 - 0
pkg/provider/senhasegura/dsm/dsm.go

@@ -90,6 +90,11 @@ func New(isoSession *senhaseguraAuth.SenhaseguraIsoSession) (*DSM, error) {
 	}, nil
 }
 
+// Not Implemented SetSecret.
+func (dsm *DSM) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 /*
 	GetSecret implements ESO interface and get a single secret from senhasegura provider with DSM service
 */

+ 5 - 0
pkg/provider/senhasegura/provider.go

@@ -43,6 +43,11 @@ const (
 	errMissingClientID            = "missing senhasegura authentication Client ID"
 )
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (p *Provider) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 /*
 	Construct a new secrets client based on provided store
 */

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

@@ -30,6 +30,7 @@ type Client struct {
 	GetSecretFn     func(context.Context, esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error)
 	GetSecretMapFn  func(context.Context, esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error)
 	GetAllSecretsFn func(context.Context, esv1beta1.ExternalSecretFind) (map[string][]byte, error)
+	SetSecretFn     func() error
 }
 
 // New returns a fake provider/client.
@@ -63,6 +64,11 @@ func (v *Client) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecret
 	return v.GetAllSecretsFn(ctx, ref)
 }
 
+// Not Implemented SetSecret.
+func (v *Client) SetSecret() error {
+	return v.SetSecretFn()
+}
+
 // GetSecret implements the provider.Provider interface.
 func (v *Client) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
 	return v.GetSecretFn(ctx, ref)
@@ -116,6 +122,11 @@ func (v *Client) WithNew(f func(context.Context, esv1beta1.GenericStore, client.
 	return v
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (v *Client) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient returns a new fake provider.
 func (v *Client) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube client.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	c, err := v.NewFn(ctx, store, kube, namespace)

+ 12 - 3
pkg/provider/vault/vault.go

@@ -224,6 +224,11 @@ type connector struct {
 	newVaultClient func(c *vault.Config) (Client, error)
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (c *connector) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 func (c *connector) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	// controller-runtime/client does not support TokenRequest or other subresource APIs
 	// so we need to construct our own client and use it to fetch tokens
@@ -350,9 +355,13 @@ func (c *connector) ValidateStore(store esv1beta1.GenericStore) error {
 	return nil
 }
 
-// Empty GetAllSecrets.
-// GetAllSecrets
-// First load all secrets from secretStore path configuration.
+// Not Implemented SetSecret.
+func (v *client) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
+// GetAllSecrets gets multiple secrets from the provider and loads into a kubernetes secret.
+// First load all secrets from secretStore path configuration
 // Then, gets secrets from a matching name or matching custom_metadata.
 func (v *client) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	if v.store.Version == esv1beta1.VaultKVStoreV1 {

+ 10 - 0
pkg/provider/webhook/webhook.go

@@ -61,6 +61,11 @@ func init() {
 	})
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (p *Provider) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube client.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	whClient := &WebHook{
 		kube:      kube,
@@ -111,6 +116,11 @@ func (w *WebHook) getStoreSecret(ctx context.Context, ref esmeta.SecretKeySelect
 	return secret, nil
 }
 
+// Not Implemented SetSecret.
+func (w *WebHook) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // Empty GetAllSecrets.
 func (w *WebHook) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented

+ 10 - 0
pkg/provider/yandex/lockbox/lockbox.go

@@ -67,6 +67,11 @@ func newLockboxProvider(yandexCloudCreator client.YandexCloudCreator) *lockboxPr
 	}
 }
 
+// Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
+func (p *lockboxProvider) Capabilities() esv1beta1.SecretStoreCapabilities {
+	return esv1beta1.SecretStoreReadOnly
+}
+
 // NewClient constructs a Yandex Lockbox Provider.
 func (p *lockboxProvider) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
 	storeSpec := store.GetSpec()
@@ -230,6 +235,11 @@ type lockboxSecretsClient struct {
 	iamToken      string
 }
 
+// Not Implemented SetSecret.
+func (c *lockboxSecretsClient) SetSecret() error {
+	return fmt.Errorf("not implemented")
+}
+
 // Empty GetAllSecrets.
 func (c *lockboxSecretsClient) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
 	// TO be implemented