diff --git a/Makefile b/Makefile
index 18e62a79a..727b1674b 100644
--- a/Makefile
+++ b/Makefile
@@ -287,15 +287,15 @@ endif
.PHONY: e2e-provider-container
e2e-provider-container:
- docker buildx build --no-cache -t $(E2E_PROVIDER_IMAGE_TAG) -f test/e2eprovider/Dockerfile --progress=plain .
+ docker buildx build --no-cache --output=type=docker -t $(E2E_PROVIDER_IMAGE_TAG) -f test/e2eprovider/Dockerfile --progress=plain .
.PHONY: container
container: crd-container
- docker buildx build --no-cache --build-arg IMAGE_VERSION=$(IMAGE_VERSION) -t $(IMAGE_TAG) -f docker/Dockerfile --progress=plain .
+ docker buildx build --no-cache --output=type=docker --build-arg IMAGE_VERSION=$(IMAGE_VERSION) -t $(IMAGE_TAG) -f docker/Dockerfile --progress=plain .
.PHONY: crd-container
crd-container: build-crds
- docker buildx build --no-cache -t $(CRD_IMAGE_TAG) -f docker/crd.Dockerfile --progress=plain _output/crds/
+ docker buildx build --no-cache --output=type=docker -t $(CRD_IMAGE_TAG) -f docker/crd.Dockerfile --progress=plain _output/crds/
.PHONY: crd-container-linux
crd-container-linux: build-crds docker-buildx-builder
@@ -462,7 +462,7 @@ e2e-eks-cleanup:
.PHONY: e2e-provider
e2e-provider:
- bats -t -T test/bats/e2e-provider.bats
+ bats -t test/bats/e2e-provider.bats
.PHONY: e2e-azure
e2e-azure: $(AZURE_CLI)
diff --git a/apis/v1/secretproviderclass_types.go b/apis/v1/secretproviderclass_types.go
index 4645c8b0a..922ccda02 100644
--- a/apis/v1/secretproviderclass_types.go
+++ b/apis/v1/secretproviderclass_types.go
@@ -44,6 +44,15 @@ type SecretObject struct {
// annotations of k8s secret object
Annotations map[string]string `json:"annotations,omitempty"`
Data []*SecretObjectData `json:"data,omitempty"`
+ // SyncAll syncs all secrets defined in the parameters field of SecretProviderClass
+ SyncAll bool `json:"syncAll,omitempty"`
+}
+
+type SyncOptions struct {
+ // syncs all secrets listed in the parameters field of SecretProviderClass
+ SyncAll bool `json:"syncAll,omitempty"`
+ // type of K8s secret object
+ Type string `json:"type,omitempty"`
}
// SecretProviderClassSpec defines the desired state of SecretProviderClass
@@ -53,6 +62,7 @@ type SecretProviderClassSpec struct {
// Configuration for specific provider
Parameters map[string]string `json:"parameters,omitempty"`
SecretObjects []*SecretObject `json:"secretObjects,omitempty"`
+ SyncOptions SyncOptions `json:"syncOptions,omitempty"`
}
// ByPodStatus defines the state of SecretProviderClass as seen by
diff --git a/charts/secrets-store-csi-driver/crds/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml b/charts/secrets-store-csi-driver/crds/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml
index 9a3bf5022..c8a5e0a7b 100644
--- a/charts/secrets-store-csi-driver/crds/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml
+++ b/charts/secrets-store-csi-driver/crds/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml
@@ -1,4 +1,3 @@
-
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
@@ -16,178 +15,203 @@ spec:
singular: secretproviderclass
scope: Namespaced
versions:
- - name: v1
- schema:
- openAPIV3Schema:
- description: SecretProviderClass is the Schema for the secretproviderclasses
- API
- 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
- properties:
- parameters:
- additionalProperties:
+ - name: v1
+ schema:
+ openAPIV3Schema:
+ description:
+ SecretProviderClass is the Schema for the secretproviderclasses
+ API
+ 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
+ properties:
+ parameters:
+ additionalProperties:
+ type: string
+ description: Configuration for specific provider
+ type: object
+ provider:
+ description: Configuration for provider name
type: string
- description: Configuration for specific provider
- type: object
- provider:
- description: Configuration for provider name
- type: string
- secretObjects:
- items:
- description: SecretObject defines the desired state of synced K8s
- secret objects
+ syncOptions:
+ description: SyncOptions defines the secret type when syncing all secrets listed in the parameters field
properties:
- annotations:
- additionalProperties:
- type: string
- description: annotations of k8s secret object
- type: object
- data:
- items:
- description: SecretObjectData defines the desired state of
- synced K8s secret object data
- properties:
- key:
- description: data field to populate
- type: string
- objectName:
- description: name of the object to sync
- type: string
- type: object
- type: array
- labels:
- additionalProperties:
- type: string
- description: labels of K8s secret object
- type: object
- secretName:
- description: name of the K8s secret object
- type: string
+ syncAll:
+ description: SyncAll as true will sync all secrets defined in the parameters field to K8s
+ type: boolean
type:
description: type of K8s secret object
type: string
type: object
- type: array
- type: object
- status:
- description: SecretProviderClassStatus defines the observed state of SecretProviderClass
- properties:
- byPod:
- items:
- description: ByPodStatus defines the state of SecretProviderClass
- as seen by an individual controller
- properties:
- id:
- description: id of the pod that wrote the status
- type: string
- namespace:
- description: namespace of the pod that wrote the status
- type: string
+ secretObjects:
+ items:
+ description:
+ SecretObject defines the desired state of synced K8s
+ secret objects
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ description: annotations of k8s secret object
+ type: object
+ syncAll:
+ description: SyncAll can sync all secrets defined in the parameters field of SecretProviderClass
+ type: boolean
+ data:
+ items:
+ description:
+ SecretObjectData defines the desired state of
+ synced K8s secret object data
+ properties:
+ key:
+ description: data field to populate
+ type: string
+ objectName:
+ description: name of the object to sync
+ type: string
+ type: object
+ type: array
+ labels:
+ additionalProperties:
+ type: string
+ description: labels of K8s secret object
+ type: object
+ secretName:
+ description: name of the K8s secret object
+ type: string
+ type:
+ description: type of K8s secret object
+ type: string
+ type: object
+ type: array
+ type: object
+ status:
+ description: SecretProviderClassStatus defines the observed state of SecretProviderClass
+ properties:
+ byPod:
+ items:
+ description:
+ ByPodStatus defines the state of SecretProviderClass
+ as seen by an individual controller
+ properties:
+ id:
+ description: id of the pod that wrote the status
+ type: string
+ namespace:
+ description: namespace of the pod that wrote the status
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: true
+ - name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description:
+ SecretProviderClass is the Schema for the secretproviderclasses
+ API
+ 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
+ properties:
+ parameters:
+ additionalProperties:
+ type: string
+ description: Configuration for specific provider
type: object
- type: array
- type: object
- type: object
- served: true
- storage: true
- - name: v1alpha1
- schema:
- openAPIV3Schema:
- description: SecretProviderClass is the Schema for the secretproviderclasses
- API
- 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
- properties:
- parameters:
- additionalProperties:
+ provider:
+ description: Configuration for provider name
type: string
- description: Configuration for specific provider
- type: object
- provider:
- description: Configuration for provider name
- type: string
- secretObjects:
- items:
- description: SecretObject defines the desired state of synced K8s
- secret objects
- properties:
- annotations:
- additionalProperties:
- type: string
- description: annotations of k8s secret object
- type: object
- data:
- items:
- description: SecretObjectData defines the desired state of
- synced K8s secret object data
- properties:
- key:
- description: data field to populate
- type: string
- objectName:
- description: name of the object to sync
- type: string
+ secretObjects:
+ items:
+ description:
+ SecretObject defines the desired state of synced K8s
+ secret objects
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ description: annotations of k8s secret object
+ type: object
+ data:
+ items:
+ description:
+ SecretObjectData defines the desired state of
+ synced K8s secret object data
+ properties:
+ key:
+ description: data field to populate
+ type: string
+ objectName:
+ description: name of the object to sync
+ type: string
+ type: object
+ type: array
+ labels:
+ additionalProperties:
+ type: string
+ description: labels of K8s secret object
type: object
- type: array
- labels:
- additionalProperties:
+ secretName:
+ description: name of the K8s secret object
type: string
- description: labels of K8s secret object
- type: object
- secretName:
- description: name of the K8s secret object
- type: string
- type:
- description: type of K8s secret object
- type: string
- type: object
- type: array
- type: object
- status:
- description: SecretProviderClassStatus defines the observed state of SecretProviderClass
- properties:
- byPod:
- items:
- description: ByPodStatus defines the state of SecretProviderClass
- as seen by an individual controller
- properties:
- id:
- description: id of the pod that wrote the status
- type: string
- namespace:
- description: namespace of the pod that wrote the status
- type: string
- type: object
- type: array
- type: object
- type: object
- served: true
- storage: false
+ type:
+ description: type of K8s secret object
+ type: string
+ type: object
+ type: array
+ type: object
+ status:
+ description: SecretProviderClassStatus defines the observed state of SecretProviderClass
+ properties:
+ byPod:
+ items:
+ description:
+ ByPodStatus defines the state of SecretProviderClass
+ as seen by an individual controller
+ properties:
+ id:
+ description: id of the pod that wrote the status
+ type: string
+ namespace:
+ description: namespace of the pod that wrote the status
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: false
status:
acceptedNames:
kind: ""
diff --git a/config/crd/bases/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml b/config/crd/bases/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml
index 9a3bf5022..c8a5e0a7b 100644
--- a/config/crd/bases/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml
+++ b/config/crd/bases/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml
@@ -1,4 +1,3 @@
-
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
@@ -16,178 +15,203 @@ spec:
singular: secretproviderclass
scope: Namespaced
versions:
- - name: v1
- schema:
- openAPIV3Schema:
- description: SecretProviderClass is the Schema for the secretproviderclasses
- API
- 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
- properties:
- parameters:
- additionalProperties:
+ - name: v1
+ schema:
+ openAPIV3Schema:
+ description:
+ SecretProviderClass is the Schema for the secretproviderclasses
+ API
+ 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
+ properties:
+ parameters:
+ additionalProperties:
+ type: string
+ description: Configuration for specific provider
+ type: object
+ provider:
+ description: Configuration for provider name
type: string
- description: Configuration for specific provider
- type: object
- provider:
- description: Configuration for provider name
- type: string
- secretObjects:
- items:
- description: SecretObject defines the desired state of synced K8s
- secret objects
+ syncOptions:
+ description: SyncOptions defines the secret type when syncing all secrets listed in the parameters field
properties:
- annotations:
- additionalProperties:
- type: string
- description: annotations of k8s secret object
- type: object
- data:
- items:
- description: SecretObjectData defines the desired state of
- synced K8s secret object data
- properties:
- key:
- description: data field to populate
- type: string
- objectName:
- description: name of the object to sync
- type: string
- type: object
- type: array
- labels:
- additionalProperties:
- type: string
- description: labels of K8s secret object
- type: object
- secretName:
- description: name of the K8s secret object
- type: string
+ syncAll:
+ description: SyncAll as true will sync all secrets defined in the parameters field to K8s
+ type: boolean
type:
description: type of K8s secret object
type: string
type: object
- type: array
- type: object
- status:
- description: SecretProviderClassStatus defines the observed state of SecretProviderClass
- properties:
- byPod:
- items:
- description: ByPodStatus defines the state of SecretProviderClass
- as seen by an individual controller
- properties:
- id:
- description: id of the pod that wrote the status
- type: string
- namespace:
- description: namespace of the pod that wrote the status
- type: string
+ secretObjects:
+ items:
+ description:
+ SecretObject defines the desired state of synced K8s
+ secret objects
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ description: annotations of k8s secret object
+ type: object
+ syncAll:
+ description: SyncAll can sync all secrets defined in the parameters field of SecretProviderClass
+ type: boolean
+ data:
+ items:
+ description:
+ SecretObjectData defines the desired state of
+ synced K8s secret object data
+ properties:
+ key:
+ description: data field to populate
+ type: string
+ objectName:
+ description: name of the object to sync
+ type: string
+ type: object
+ type: array
+ labels:
+ additionalProperties:
+ type: string
+ description: labels of K8s secret object
+ type: object
+ secretName:
+ description: name of the K8s secret object
+ type: string
+ type:
+ description: type of K8s secret object
+ type: string
+ type: object
+ type: array
+ type: object
+ status:
+ description: SecretProviderClassStatus defines the observed state of SecretProviderClass
+ properties:
+ byPod:
+ items:
+ description:
+ ByPodStatus defines the state of SecretProviderClass
+ as seen by an individual controller
+ properties:
+ id:
+ description: id of the pod that wrote the status
+ type: string
+ namespace:
+ description: namespace of the pod that wrote the status
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: true
+ - name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description:
+ SecretProviderClass is the Schema for the secretproviderclasses
+ API
+ 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
+ properties:
+ parameters:
+ additionalProperties:
+ type: string
+ description: Configuration for specific provider
type: object
- type: array
- type: object
- type: object
- served: true
- storage: true
- - name: v1alpha1
- schema:
- openAPIV3Schema:
- description: SecretProviderClass is the Schema for the secretproviderclasses
- API
- 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
- properties:
- parameters:
- additionalProperties:
+ provider:
+ description: Configuration for provider name
type: string
- description: Configuration for specific provider
- type: object
- provider:
- description: Configuration for provider name
- type: string
- secretObjects:
- items:
- description: SecretObject defines the desired state of synced K8s
- secret objects
- properties:
- annotations:
- additionalProperties:
- type: string
- description: annotations of k8s secret object
- type: object
- data:
- items:
- description: SecretObjectData defines the desired state of
- synced K8s secret object data
- properties:
- key:
- description: data field to populate
- type: string
- objectName:
- description: name of the object to sync
- type: string
+ secretObjects:
+ items:
+ description:
+ SecretObject defines the desired state of synced K8s
+ secret objects
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ description: annotations of k8s secret object
+ type: object
+ data:
+ items:
+ description:
+ SecretObjectData defines the desired state of
+ synced K8s secret object data
+ properties:
+ key:
+ description: data field to populate
+ type: string
+ objectName:
+ description: name of the object to sync
+ type: string
+ type: object
+ type: array
+ labels:
+ additionalProperties:
+ type: string
+ description: labels of K8s secret object
type: object
- type: array
- labels:
- additionalProperties:
+ secretName:
+ description: name of the K8s secret object
type: string
- description: labels of K8s secret object
- type: object
- secretName:
- description: name of the K8s secret object
- type: string
- type:
- description: type of K8s secret object
- type: string
- type: object
- type: array
- type: object
- status:
- description: SecretProviderClassStatus defines the observed state of SecretProviderClass
- properties:
- byPod:
- items:
- description: ByPodStatus defines the state of SecretProviderClass
- as seen by an individual controller
- properties:
- id:
- description: id of the pod that wrote the status
- type: string
- namespace:
- description: namespace of the pod that wrote the status
- type: string
- type: object
- type: array
- type: object
- type: object
- served: true
- storage: false
+ type:
+ description: type of K8s secret object
+ type: string
+ type: object
+ type: array
+ type: object
+ status:
+ description: SecretProviderClassStatus defines the observed state of SecretProviderClass
+ properties:
+ byPod:
+ items:
+ description:
+ ByPodStatus defines the state of SecretProviderClass
+ as seen by an individual controller
+ properties:
+ id:
+ description: id of the pod that wrote the status
+ type: string
+ namespace:
+ description: namespace of the pod that wrote the status
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: false
status:
acceptedNames:
kind: ""
diff --git a/controllers/secretproviderclasspodstatus_controller.go b/controllers/secretproviderclasspodstatus_controller.go
index c327459fa..a873cd82b 100644
--- a/controllers/secretproviderclasspodstatus_controller.go
+++ b/controllers/secretproviderclasspodstatus_controller.go
@@ -45,6 +45,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/predicate"
+ "sigs.k8s.io/secrets-store-csi-driver/pkg/util/spcutil"
)
const (
@@ -115,7 +116,7 @@ func (r *SecretProviderClassPodStatusReconciler) Patcher(ctx context.Context) er
}
spcPodStatuses := spcPodStatusList.Items
- for i := range spcPodStatuses {
+ for i, spcPodStatus := range spcPodStatuses {
spcName := spcPodStatuses[i].Status.SecretProviderClassName
spc := &secretsstorev1.SecretProviderClass{}
namespace := spcPodStatuses[i].Namespace
@@ -161,6 +162,19 @@ func (r *SecretProviderClassPodStatusReconciler) Patcher(ctx context.Context) er
ownerRefs = append(ownerRefs, ref)
}
+ if spc.Spec.SyncOptions.SyncAll {
+ files, err := fileutil.GetMountedFiles(spcPodStatus.Status.TargetPath)
+ if err != nil {
+ return fmt.Errorf("failed to get mounted files for pod %s/%s: %v", namespace, pod.Name, err)
+ } else {
+ if len(spc.Spec.SecretObjects) == 0 {
+ spc.Spec.SecretObjects = spcutil.BuildSecretObjects(files, secretutil.GetSecretType(strings.TrimSpace(spc.Spec.SyncOptions.Type)))
+ } else {
+ spc.Spec.SecretObjects = append(spc.Spec.SecretObjects, spcutil.BuildSecretObjects(files, secretutil.GetSecretType(strings.TrimSpace(spc.Spec.SyncOptions.Type)))...)
+ }
+ }
+ }
+
for _, secret := range spc.Spec.SecretObjects {
key := types.NamespacedName{Name: secret.SecretName, Namespace: namespace}
val, exists := secretOwnerMap[key]
@@ -258,7 +272,7 @@ func (r *SecretProviderClassPodStatusReconciler) Reconcile(ctx context.Context,
return ctrl.Result{}, err
}
- if len(spc.Spec.SecretObjects) == 0 {
+ if len(spc.Spec.SecretObjects) == 0 && !spc.Spec.SyncOptions.SyncAll {
klog.InfoS("no secret objects defined for spc, nothing to reconcile", "spc", klog.KObj(spc), "spcps", klog.KObj(spcPodStatus))
return ctrl.Result{}, nil
}
@@ -283,6 +297,25 @@ func (r *SecretProviderClassPodStatusReconciler) Reconcile(ctx context.Context,
klog.ErrorS(err, "failed to get mounted files", "spc", klog.KObj(spc), "pod", klog.KObj(pod), "spcps", klog.KObj(spcPodStatus))
return ctrl.Result{RequeueAfter: 10 * time.Second}, err
}
+
+ if spc.Spec.SyncOptions.SyncAll {
+ if len(spc.Spec.SecretObjects) == 0 {
+ spc.Spec.SecretObjects = spcutil.BuildSecretObjects(files, secretutil.GetSecretType(strings.TrimSpace(spc.Spec.SyncOptions.Type)))
+ } else {
+ spc.Spec.SecretObjects = append(spc.Spec.SecretObjects, spcutil.BuildSecretObjects(files, secretutil.GetSecretType(strings.TrimSpace(spc.Spec.SyncOptions.Type)))...)
+ }
+ }
+
+ for _, secretObj := range spc.Spec.SecretObjects {
+ if secretObj.SyncAll {
+ if secretutil.GetSecretType(strings.TrimSpace(secretObj.Type)) != corev1.SecretTypeOpaque {
+ return ctrl.Result{}, fmt.Errorf("secret provider class %s/%s cannot use secretObjects[*].syncAll for non-opaque secrets", spc.Namespace, spc.Name)
+ }
+
+ spcutil.BuildSecretObjectData(files, secretObj)
+ }
+ }
+
errs := make([]error, 0)
for _, secretObj := range spc.Spec.SecretObjects {
secretName := strings.TrimSpace(secretObj.SecretName)
diff --git a/deploy/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml b/deploy/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml
index 9a3bf5022..c8a5e0a7b 100644
--- a/deploy/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml
+++ b/deploy/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml
@@ -1,4 +1,3 @@
-
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
@@ -16,178 +15,203 @@ spec:
singular: secretproviderclass
scope: Namespaced
versions:
- - name: v1
- schema:
- openAPIV3Schema:
- description: SecretProviderClass is the Schema for the secretproviderclasses
- API
- 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
- properties:
- parameters:
- additionalProperties:
+ - name: v1
+ schema:
+ openAPIV3Schema:
+ description:
+ SecretProviderClass is the Schema for the secretproviderclasses
+ API
+ 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
+ properties:
+ parameters:
+ additionalProperties:
+ type: string
+ description: Configuration for specific provider
+ type: object
+ provider:
+ description: Configuration for provider name
type: string
- description: Configuration for specific provider
- type: object
- provider:
- description: Configuration for provider name
- type: string
- secretObjects:
- items:
- description: SecretObject defines the desired state of synced K8s
- secret objects
+ syncOptions:
+ description: SyncOptions defines the secret type when syncing all secrets listed in the parameters field
properties:
- annotations:
- additionalProperties:
- type: string
- description: annotations of k8s secret object
- type: object
- data:
- items:
- description: SecretObjectData defines the desired state of
- synced K8s secret object data
- properties:
- key:
- description: data field to populate
- type: string
- objectName:
- description: name of the object to sync
- type: string
- type: object
- type: array
- labels:
- additionalProperties:
- type: string
- description: labels of K8s secret object
- type: object
- secretName:
- description: name of the K8s secret object
- type: string
+ syncAll:
+ description: SyncAll as true will sync all secrets defined in the parameters field to K8s
+ type: boolean
type:
description: type of K8s secret object
type: string
type: object
- type: array
- type: object
- status:
- description: SecretProviderClassStatus defines the observed state of SecretProviderClass
- properties:
- byPod:
- items:
- description: ByPodStatus defines the state of SecretProviderClass
- as seen by an individual controller
- properties:
- id:
- description: id of the pod that wrote the status
- type: string
- namespace:
- description: namespace of the pod that wrote the status
- type: string
+ secretObjects:
+ items:
+ description:
+ SecretObject defines the desired state of synced K8s
+ secret objects
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ description: annotations of k8s secret object
+ type: object
+ syncAll:
+ description: SyncAll can sync all secrets defined in the parameters field of SecretProviderClass
+ type: boolean
+ data:
+ items:
+ description:
+ SecretObjectData defines the desired state of
+ synced K8s secret object data
+ properties:
+ key:
+ description: data field to populate
+ type: string
+ objectName:
+ description: name of the object to sync
+ type: string
+ type: object
+ type: array
+ labels:
+ additionalProperties:
+ type: string
+ description: labels of K8s secret object
+ type: object
+ secretName:
+ description: name of the K8s secret object
+ type: string
+ type:
+ description: type of K8s secret object
+ type: string
+ type: object
+ type: array
+ type: object
+ status:
+ description: SecretProviderClassStatus defines the observed state of SecretProviderClass
+ properties:
+ byPod:
+ items:
+ description:
+ ByPodStatus defines the state of SecretProviderClass
+ as seen by an individual controller
+ properties:
+ id:
+ description: id of the pod that wrote the status
+ type: string
+ namespace:
+ description: namespace of the pod that wrote the status
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: true
+ - name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description:
+ SecretProviderClass is the Schema for the secretproviderclasses
+ API
+ 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
+ properties:
+ parameters:
+ additionalProperties:
+ type: string
+ description: Configuration for specific provider
type: object
- type: array
- type: object
- type: object
- served: true
- storage: true
- - name: v1alpha1
- schema:
- openAPIV3Schema:
- description: SecretProviderClass is the Schema for the secretproviderclasses
- API
- 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
- properties:
- parameters:
- additionalProperties:
+ provider:
+ description: Configuration for provider name
type: string
- description: Configuration for specific provider
- type: object
- provider:
- description: Configuration for provider name
- type: string
- secretObjects:
- items:
- description: SecretObject defines the desired state of synced K8s
- secret objects
- properties:
- annotations:
- additionalProperties:
- type: string
- description: annotations of k8s secret object
- type: object
- data:
- items:
- description: SecretObjectData defines the desired state of
- synced K8s secret object data
- properties:
- key:
- description: data field to populate
- type: string
- objectName:
- description: name of the object to sync
- type: string
+ secretObjects:
+ items:
+ description:
+ SecretObject defines the desired state of synced K8s
+ secret objects
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ description: annotations of k8s secret object
+ type: object
+ data:
+ items:
+ description:
+ SecretObjectData defines the desired state of
+ synced K8s secret object data
+ properties:
+ key:
+ description: data field to populate
+ type: string
+ objectName:
+ description: name of the object to sync
+ type: string
+ type: object
+ type: array
+ labels:
+ additionalProperties:
+ type: string
+ description: labels of K8s secret object
type: object
- type: array
- labels:
- additionalProperties:
+ secretName:
+ description: name of the K8s secret object
type: string
- description: labels of K8s secret object
- type: object
- secretName:
- description: name of the K8s secret object
- type: string
- type:
- description: type of K8s secret object
- type: string
- type: object
- type: array
- type: object
- status:
- description: SecretProviderClassStatus defines the observed state of SecretProviderClass
- properties:
- byPod:
- items:
- description: ByPodStatus defines the state of SecretProviderClass
- as seen by an individual controller
- properties:
- id:
- description: id of the pod that wrote the status
- type: string
- namespace:
- description: namespace of the pod that wrote the status
- type: string
- type: object
- type: array
- type: object
- type: object
- served: true
- storage: false
+ type:
+ description: type of K8s secret object
+ type: string
+ type: object
+ type: array
+ type: object
+ status:
+ description: SecretProviderClassStatus defines the observed state of SecretProviderClass
+ properties:
+ byPod:
+ items:
+ description:
+ ByPodStatus defines the state of SecretProviderClass
+ as seen by an individual controller
+ properties:
+ id:
+ description: id of the pod that wrote the status
+ type: string
+ namespace:
+ description: namespace of the pod that wrote the status
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: false
status:
acceptedNames:
kind: ""
diff --git a/docs/book/src/topics/sync-all-secrets-to-k8s.md b/docs/book/src/topics/sync-all-secrets-to-k8s.md
new file mode 100644
index 000000000..fb252f2a5
--- /dev/null
+++ b/docs/book/src/topics/sync-all-secrets-to-k8s.md
@@ -0,0 +1,496 @@
+# Sync All Secrets to K8s
+
+
+Opaque Examples
+
+- In this example, we can expect the secrets that are mounted on the paths `/mnt/secrets-store/username` and `/mnt/secrets-store/password` to be synced to K8s individually.
+- The value of `objectName` is the name of the K8s secret
+
+
+```yaml
+apiVersion: secrets-store.csi.x-k8s.io/v1
+kind: SecretProviderClass
+metadata:
+ name: vault-opaque
+spec:
+ provider: vault
+ parameters:
+ roleName: "csi"
+ vaultAddress: "http://vault.vault:8200"
+ objects: |
+ - secretPath: "secret/data/db-creds"
+ objectName: "username"
+ secretKey: "username"
+ - secretPath: "secret/data/db-creds"
+ objectName: "password"
+ secretKey: "password"
+ syncOptions:
+ syncAll: true
+ type: Opaque
+---
+kind: ServiceAccount
+apiVersion: v1
+metadata:
+ name: opaque-sa
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: busybox-deployment-opaque
+ labels:
+ app: busybox
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: busybox
+ template:
+ metadata:
+ labels:
+ app: busybox
+ spec:
+ terminationGracePeriodSeconds: 0
+ serviceAccountName: opaque-sa
+ containers:
+ - image: k8s.gcr.io/e2e-test-images/busybox:1.29
+ name: busybox
+ imagePullPolicy: IfNotPresent
+ command:
+ - "/bin/sleep"
+ - "10000"
+ env:
+ - name: DB_USER
+ valueFrom:
+ secretKeyRef:
+ name: username
+ key: username
+ - name: DB_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: password
+ key: password
+ volumeMounts:
+ - name: secrets-store-inline
+ mountPath: "/mnt/secrets-store"
+ readOnly: true
+ volumes:
+ - name: secrets-store-inline
+ csi:
+ driver: secrets-store.csi.k8s.io
+ readOnly: true
+ volumeAttributes:
+ secretProviderClass: "vault-opaque"
+
+```
+
+- In this example, we are nesting some secrets further into the filesystem. Since K8s secrets must have unique names, the name of the synced secret will be a hyphen-separated version of the `objectName` value.
+- In this case, we can expect the following secrets in K8s
+1. username
+2. password
+3. nested-username
+4. nested-password
+
+- You will also notice that we have one item in the `.spec.secretObjects` field. With `Opaque` type secrets, we can sync all mounted secrets into a single K8s secret. **This does not work with other secret types**
+- In this example, we can expect a K8s secret named `db-secret` with the following keys
+1. username
+2. password
+3. nested-username
+4. nested-password
+
+```yaml
+apiVersion: secrets-store.csi.x-k8s.io/v1
+kind: SecretProviderClass
+metadata:
+ name: vault-opaque
+spec:
+ provider: vault
+ parameters:
+ roleName: "csi"
+ vaultAddress: "http://vault.vault:8200"
+ objects: |
+ - secretPath: "secret/data/db-creds"
+ objectName: "username"
+ secretKey: "username"
+ - secretPath: "secret/data/db-creds"
+ objectName: "password"
+ secretKey: "password"
+ - secretPath: "secret/data/db-creds"
+ objectName: "nested/username"
+ secretKey: "username"
+ - secretPath: "secret/data/db-creds"
+ objectName: "nested/password"
+ secretKey: "password"
+ syncOptions:
+ type: Opaque
+ syncAll: true
+ secretObjects:
+ - secretName: db-secret
+ type: Opaque
+ syncAll: true
+---
+kind: ServiceAccount
+apiVersion: v1
+metadata:
+ name: opaque-sa
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: busybox-deployment-opaque
+ labels:
+ app: busybox
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: busybox
+ template:
+ metadata:
+ labels:
+ app: busybox
+ spec:
+ terminationGracePeriodSeconds: 0
+ serviceAccountName: opaque-sa
+ containers:
+ - image: k8s.gcr.io/e2e-test-images/busybox:1.29
+ name: busybox
+ imagePullPolicy: IfNotPresent
+ command:
+ - "/bin/sleep"
+ - "10000"
+ env:
+ - name: DB_USER
+ valueFrom:
+ secretKeyRef:
+ name: username
+ key: username
+ - name: DB_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: password
+ key: password
+ - name: DB_NESTED_USER
+ valueFrom:
+ secretKeyRef:
+ name: nested-username
+ key: username
+ - name: DB_NESTED_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: nested-password
+ key: password
+ - name: DB_SECRET_USER
+ valueFrom:
+ secretKeyRef:
+ name: db-secret
+ key: username
+ - name: DB_SECRET_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: db-secret
+ key: password
+ - name: DB_SECRET_NESTED_USER
+ valueFrom:
+ secretKeyRef:
+ name: db-secret
+ key: username
+ - name: DB_SECRET_NESTED_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: db-secret
+ key: password
+ volumeMounts:
+ - name: secrets-store-inline
+ mountPath: "/mnt/secrets-store"
+ readOnly: true
+ volumes:
+ - name: secrets-store-inline
+ csi:
+ driver: secrets-store.csi.k8s.io
+ readOnly: true
+ volumeAttributes:
+ secretProviderClass: "vault-opaque"
+
+```
+
+
+
+
+TLS Examples
+
+- For TLS secrets, you need to mount the certificate and private key on a single mount as shown in the example below.
+- The driver will separate the two values and assign them to the `tls.crt` and `tls.key` keys respectively.
+
+```yaml
+apiVersion: secrets-store.csi.x-k8s.io/v1
+kind: SecretProviderClass
+metadata:
+ name: vault-tls
+spec:
+ provider: vault
+ parameters:
+ roleName: "csi"
+ vaultAddress: "http://vault.vault:8200"
+ objects: |
+ - secretPath: "secret/data/certs"
+ objectName: "cert1"
+ secretKey: "cert1"
+ - secretPath: "secret/data/certs"
+ objectName: "cert2"
+ secretKey: "cert2"
+ syncOptions:
+ syncAll: true
+ type: kubernetes.io/tls
+---
+kind: ServiceAccount
+apiVersion: v1
+metadata:
+ name: tls-sa
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: busybox-deployment-tls
+ labels:
+ app: busybox-tls
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: busybox-tls
+ template:
+ metadata:
+ labels:
+ app: busybox-tls
+ spec:
+ terminationGracePeriodSeconds: 0
+ serviceAccountName: tls-sa
+ containers:
+ - image: k8s.gcr.io/e2e-test-images/busybox:1.29
+ name: busybox-tls
+ imagePullPolicy: IfNotPresent
+ command:
+ - "/bin/sleep"
+ - "10000"
+ env:
+ - name: PRIVATE_KEY_1
+ valueFrom:
+ secretKeyRef:
+ name: cert1
+ key: tls.key
+ - name: CERTIFICATE_1
+ valueFrom:
+ secretKeyRef:
+ name: cert1
+ key: tls.crt
+ - name: PRIVATE_KEY_2
+ valueFrom:
+ secretKeyRef:
+ name: cert2
+ key: tls.key
+ - name: CERTIFICATE_2
+ valueFrom:
+ secretKeyRef:
+ name: cert2
+ key: tls.crt
+ volumeMounts:
+ - name: secrets-store-inline
+ mountPath: "/mnt/secrets-store"
+ readOnly: true
+ volumes:
+ - name: secrets-store-inline
+ csi:
+ driver: secrets-store.csi.k8s.io
+ readOnly: true
+ volumeAttributes:
+ secretProviderClass: "vault-tls"
+```
+
+```txt
+-----BEGIN CERTIFICATE-----
+MIIDOTCCAiGgAwIBAgIJAP0J5Z7N0Y5fMA0GCSqGSIb3DQEBCwUAMDMxFzAVBgNV
+BAMMDmRlbW8uYXp1cmUuY29tMRgwFgYDVQQKDA9ha3MtaW5ncmVzcy10bHMwHhcN
+MjAwNDE1MDQyMzQ2WhcNMjEwNDE1MDQyMzQ2WjAzMRcwFQYDVQQDDA5kZW1vLmF6
+dXJlLmNvbTEYMBYGA1UECgwPYWtzLWluZ3Jlc3MtdGxzMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAyS3Zky3n8JlLBxPLzgUpKZYxvzRadeWLmWVbK9by
+o08S0Ss8Jao7Ay1wHtnLbn52rzCX6IX1sAe1TAT755Gk7JtLMkshtj6F8BNeelEy
+E1gsBE5ntY5vyLTm/jZUIKz2Z9TLnqvQTmp6gJ68BKJ1NobnsHiAcKc6hI7kmY9C
+oshmAi5qiKYBgzv/thji0093vtVSa9iwHhQp+AEIMhkvM5ZZkiU5eE6MT9SBEcVW
+KmWF28UsB04daYwS2MKJ5l6d4n0LUdAG0FBt1lCoT9rwUDj9l3Mqmi953gw26LUr
+NrYnM/8N2jl7Cuyw5alIWaUDrt5i+pu8wdWfzVk+fO7x8QIDAQABo1AwTjAdBgNV
+HQ4EFgQUwFBbR014McETdrGGklpEQcl71Q0wHwYDVR0jBBgwFoAUwFBbR014McET
+drGGklpEQcl71Q0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEATgTy
+gg1Q6ISSekiBCe12dqUTMFQh9GKpfYWKRbMtjOjpc7Mdwkdmm3Fu6l3RfEFT28Ij
+fy97LMYv8W7beemDFqdmneb2w2ww0ZAFJg+GqIJZ9s/JadiFBDNU7CmJMhA225Qz
+XC8ovejiePslnL4QJWlhVG93ZlBJ6SDkRgfcoIW2x4IBE6wv7jmRF4lOvb3z1ddP
+iPQqhbEEbwMpXmWv7/2RnjAHdjdGaWRMC5+CaI+lqHyj6ir1c+e6u1QUY54qjmgM
+koN/frqYab5Ek3kauj1iqW7rPkrFCqT2evh0YRqb1bFsCLJrRNxnOZ5wKXV/OYQa
+QX5t0wFGCZ0KlbXDiw==
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDJLdmTLefwmUsH
+E8vOBSkpljG/NFp15YuZZVsr1vKjTxLRKzwlqjsDLXAe2ctufnavMJfohfWwB7VM
+BPvnkaTsm0sySyG2PoXwE156UTITWCwETme1jm/ItOb+NlQgrPZn1Mueq9BOanqA
+nrwEonU2hueweIBwpzqEjuSZj0KiyGYCLmqIpgGDO/+2GOLTT3e+1VJr2LAeFCn4
+AQgyGS8zllmSJTl4ToxP1IERxVYqZYXbxSwHTh1pjBLYwonmXp3ifQtR0AbQUG3W
+UKhP2vBQOP2XcyqaL3neDDbotSs2ticz/w3aOXsK7LDlqUhZpQOu3mL6m7zB1Z/N
+WT587vHxAgMBAAECggEAJb0qIYftCJ9ZCbzW8JDbRefc8SdbCN7Er0PqNHEgFy6Q
+MxjPMambZF8ztzXYCaRDk12kQYRPsHPhuJ7+ulQCAjinhIm/izZzXbPkd0GgCSzz
+JOOoZNCRe68j3fBHG9IWbyfmAp/sdalXzaT5VE09e7sW323bekaEnbVIgN30/CAS
+gI77YdaIhG+PT/pSCOc11MTkBJp+VhT1tEtlRAR78b1RXbGi1oUHRee7C3Ia8IKQ
+3L5dPxR9RsYsR2O66908kEi8ZcuIjcbIuRPDXYHY+5Nwm3mXuZlkyjyfxJXsIA8i
+qBrQrSpHGgAn1TVlLDSCKPLbkRzBRRvAW0zL/cDTuQKBgQDq/9Yxx9QivAuUxxdE
+u0VO5CzzZYFWhDxAXS3/wYyo1YnoPtUz/lGCvMWp0k2aaa0+KTXv2fRCUGSujHW7
+Jfo4kuMPkauAhoXx9QJAcjoK0nNbYEaqoJyMoRID+Qb9XHkj+lmBTmMVgALCT9DI
+HekHj/M3b7CknbfWv1sOZ/vpQwKBgQDbKEuP/DWQa9DC5nn5phHD/LWZLG/cMR4X
+TmwM/cbfRxM/6W0+/KLAodz4amGRzVlW6ax4k26BSE8Zt/SiyA1DQRTeFloduoqW
+iWF4dMeItxw2am+xLREwtoN3FgsJHu2z/O/0aaBAOMLUXIPIyiE4L6OnEPifE/pb
+AM8EbM5auwKBgGhdABIRjbtzSa1kEYhbprcXjIL3lE4I4f0vpIsNuNsOInW62dKC
+Yk6uaRY3KHGn9uFBSgvf/qMost310R8xCYPwb9htN/4XQAspZTubvv0pY0O0aQ3D
+0GJ/8dFD2f/Q/pekyfUsC8Lzm8YRzkXhSqkqG7iF6Kviw08iolyuf2ijAoGBANaA
+pRzDvWWisUziKsa3zbGnGdNXVBEPniUvo8A/b7RAK84lWcEJov6qLs6RyPfdJrFT
+u3S00LcHICzLCU1+QsTt4U/STtfEKjtXMailnFrq5lk4aiPfOXEVYq1fTOPbesrt
+Katu6uOQ6tjRyEbx1/vXXPV7Peztr9/8daMeIAdbAoGBAOYRJ1CzMYQKjWF32Uas
+7hhQxyH1QI4nV56Dryq7l/UWun2pfwNLZFqOHD3qm05aznzNKvk9aHAsOPFfUUXO
+7sp0Ge5FLMSw1uMNnutcVcMz37KAY2fOoE2xoLM4DU/H2NqDjeGCsOsU1ReRS1vB
+J+42JGwBdLV99ruYKVKOWPh4
+-----END PRIVATE KEY-----
+```
+
+
+
+
+Basic Auth Examples
+
+- Basic Auth secrets require values for the `username` and `password` keys in K8s.
+- In your secret store of choice, these values should be comma-separated as a single value - `myusername,mypassword`.
+- The driver will separate the two values and assign them to the `username` and `password` keys respectively.
+
+```yaml
+apiVersion: secrets-store.csi.x-k8s.io/v1
+kind: SecretProviderClass
+metadata:
+ name: vault-basic
+spec:
+ provider: vault
+ parameters:
+ roleName: "csi"
+ vaultAddress: "http://vault.vault:8200"
+ objects: |
+ - secretPath: "secret/data/basic1"
+ objectName: "basic/basic1"
+ secretKey: "credentials"
+ - secretPath: "secret/data/basic2"
+ objectName: "basic/basic2"
+ secretKey: "credentials"
+ - secretPath: "secret/data/basic3"
+ objectName: "basic/basic3"
+ secretKey: "credentials"
+ syncOptions:
+ syncAll: true
+ type: kubernetes.io/basic-auth
+---
+kind: ServiceAccount
+apiVersion: v1
+metadata:
+ name: basic-sa
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: busybox-deployment-basic
+ labels:
+ app: busybox-basic
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: busybox-basic
+ template:
+ metadata:
+ labels:
+ app: busybox-basic
+ spec:
+ terminationGracePeriodSeconds: 0
+ serviceAccountName: basic-sa
+ containers:
+ - image: k8s.gcr.io/e2e-test-images/busybox:1.29
+ name: busybox-tls
+ imagePullPolicy: IfNotPresent
+ command:
+ - "/bin/sleep"
+ - "10000"
+ env:
+ - name: BASIC_USERNAME_1
+ valueFrom:
+ secretKeyRef:
+ name: basic-basic1
+ key: username
+ - name: BASIC_PASSWORD_1
+ valueFrom:
+ secretKeyRef:
+ name: basic-basic1
+ key: password
+ - name: BASIC_USERNAME_2
+ valueFrom:
+ secretKeyRef:
+ name: basic-basic2
+ key: username
+ - name: BASIC_PASSWORD_2
+ valueFrom:
+ secretKeyRef:
+ name: basic-basic2
+ key: password
+ - name: BASIC_USERNAME_3
+ valueFrom:
+ secretKeyRef:
+ name: basic-basic3
+ key: username
+ - name: BASIC_PASSWORD_3
+ valueFrom:
+ secretKeyRef:
+ name: basic-basic3
+ key: password
+ volumeMounts:
+ - name: secrets-store-inline
+ mountPath: "/mnt/secrets-store"
+ readOnly: true
+ volumes:
+ - name: secrets-store-inline
+ csi:
+ driver: secrets-store.csi.k8s.io
+ readOnly: true
+ volumeAttributes:
+ secretProviderClass: "vault-basic"
+
+```
+
+
+
+You may know already that you want to sync all your secrets to K8s using the CSI driver, but adding each secret to the SecretProviderClass configuration can be time-consuming and error-prone. In this case, you can tell the driver to sync all mounted secrets to K8s with the **SyncAll** option.
+
+> NOTE: This feature is only available for secrets-store.csi.x-k8s.io/v1
+
+See the full examples above to get a better understanding for the configuration shown:
+
+```yaml
+apiVersion: secrets-store.csi.x-k8s.io/v1
+kind: SecretProviderClass
+metadata:
+ name: vault-opaque
+spec:
+ provider: vault
+ parameters:
+ roleName: "csi"
+ vaultAddress: "http://vault.vault:8200"
+ objects: |
+ - secretPath: "secret/data/db-creds"
+ objectName: "username"
+ secretKey: "username"
+ - secretPath: "secret/data/db-creds"
+ objectName: "password"
+ secretKey: "password"
+ syncOptions:
+ syncAll: true
+ type: Opaque
+```
\ No newline at end of file
diff --git a/manifest_staging/charts/secrets-store-csi-driver/crds/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml b/manifest_staging/charts/secrets-store-csi-driver/crds/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml
index 9a3bf5022..c8a5e0a7b 100644
--- a/manifest_staging/charts/secrets-store-csi-driver/crds/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml
+++ b/manifest_staging/charts/secrets-store-csi-driver/crds/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml
@@ -1,4 +1,3 @@
-
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
@@ -16,178 +15,203 @@ spec:
singular: secretproviderclass
scope: Namespaced
versions:
- - name: v1
- schema:
- openAPIV3Schema:
- description: SecretProviderClass is the Schema for the secretproviderclasses
- API
- 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
- properties:
- parameters:
- additionalProperties:
+ - name: v1
+ schema:
+ openAPIV3Schema:
+ description:
+ SecretProviderClass is the Schema for the secretproviderclasses
+ API
+ 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
+ properties:
+ parameters:
+ additionalProperties:
+ type: string
+ description: Configuration for specific provider
+ type: object
+ provider:
+ description: Configuration for provider name
type: string
- description: Configuration for specific provider
- type: object
- provider:
- description: Configuration for provider name
- type: string
- secretObjects:
- items:
- description: SecretObject defines the desired state of synced K8s
- secret objects
+ syncOptions:
+ description: SyncOptions defines the secret type when syncing all secrets listed in the parameters field
properties:
- annotations:
- additionalProperties:
- type: string
- description: annotations of k8s secret object
- type: object
- data:
- items:
- description: SecretObjectData defines the desired state of
- synced K8s secret object data
- properties:
- key:
- description: data field to populate
- type: string
- objectName:
- description: name of the object to sync
- type: string
- type: object
- type: array
- labels:
- additionalProperties:
- type: string
- description: labels of K8s secret object
- type: object
- secretName:
- description: name of the K8s secret object
- type: string
+ syncAll:
+ description: SyncAll as true will sync all secrets defined in the parameters field to K8s
+ type: boolean
type:
description: type of K8s secret object
type: string
type: object
- type: array
- type: object
- status:
- description: SecretProviderClassStatus defines the observed state of SecretProviderClass
- properties:
- byPod:
- items:
- description: ByPodStatus defines the state of SecretProviderClass
- as seen by an individual controller
- properties:
- id:
- description: id of the pod that wrote the status
- type: string
- namespace:
- description: namespace of the pod that wrote the status
- type: string
+ secretObjects:
+ items:
+ description:
+ SecretObject defines the desired state of synced K8s
+ secret objects
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ description: annotations of k8s secret object
+ type: object
+ syncAll:
+ description: SyncAll can sync all secrets defined in the parameters field of SecretProviderClass
+ type: boolean
+ data:
+ items:
+ description:
+ SecretObjectData defines the desired state of
+ synced K8s secret object data
+ properties:
+ key:
+ description: data field to populate
+ type: string
+ objectName:
+ description: name of the object to sync
+ type: string
+ type: object
+ type: array
+ labels:
+ additionalProperties:
+ type: string
+ description: labels of K8s secret object
+ type: object
+ secretName:
+ description: name of the K8s secret object
+ type: string
+ type:
+ description: type of K8s secret object
+ type: string
+ type: object
+ type: array
+ type: object
+ status:
+ description: SecretProviderClassStatus defines the observed state of SecretProviderClass
+ properties:
+ byPod:
+ items:
+ description:
+ ByPodStatus defines the state of SecretProviderClass
+ as seen by an individual controller
+ properties:
+ id:
+ description: id of the pod that wrote the status
+ type: string
+ namespace:
+ description: namespace of the pod that wrote the status
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: true
+ - name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description:
+ SecretProviderClass is the Schema for the secretproviderclasses
+ API
+ 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
+ properties:
+ parameters:
+ additionalProperties:
+ type: string
+ description: Configuration for specific provider
type: object
- type: array
- type: object
- type: object
- served: true
- storage: true
- - name: v1alpha1
- schema:
- openAPIV3Schema:
- description: SecretProviderClass is the Schema for the secretproviderclasses
- API
- 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
- properties:
- parameters:
- additionalProperties:
+ provider:
+ description: Configuration for provider name
type: string
- description: Configuration for specific provider
- type: object
- provider:
- description: Configuration for provider name
- type: string
- secretObjects:
- items:
- description: SecretObject defines the desired state of synced K8s
- secret objects
- properties:
- annotations:
- additionalProperties:
- type: string
- description: annotations of k8s secret object
- type: object
- data:
- items:
- description: SecretObjectData defines the desired state of
- synced K8s secret object data
- properties:
- key:
- description: data field to populate
- type: string
- objectName:
- description: name of the object to sync
- type: string
+ secretObjects:
+ items:
+ description:
+ SecretObject defines the desired state of synced K8s
+ secret objects
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ description: annotations of k8s secret object
+ type: object
+ data:
+ items:
+ description:
+ SecretObjectData defines the desired state of
+ synced K8s secret object data
+ properties:
+ key:
+ description: data field to populate
+ type: string
+ objectName:
+ description: name of the object to sync
+ type: string
+ type: object
+ type: array
+ labels:
+ additionalProperties:
+ type: string
+ description: labels of K8s secret object
type: object
- type: array
- labels:
- additionalProperties:
+ secretName:
+ description: name of the K8s secret object
type: string
- description: labels of K8s secret object
- type: object
- secretName:
- description: name of the K8s secret object
- type: string
- type:
- description: type of K8s secret object
- type: string
- type: object
- type: array
- type: object
- status:
- description: SecretProviderClassStatus defines the observed state of SecretProviderClass
- properties:
- byPod:
- items:
- description: ByPodStatus defines the state of SecretProviderClass
- as seen by an individual controller
- properties:
- id:
- description: id of the pod that wrote the status
- type: string
- namespace:
- description: namespace of the pod that wrote the status
- type: string
- type: object
- type: array
- type: object
- type: object
- served: true
- storage: false
+ type:
+ description: type of K8s secret object
+ type: string
+ type: object
+ type: array
+ type: object
+ status:
+ description: SecretProviderClassStatus defines the observed state of SecretProviderClass
+ properties:
+ byPod:
+ items:
+ description:
+ ByPodStatus defines the state of SecretProviderClass
+ as seen by an individual controller
+ properties:
+ id:
+ description: id of the pod that wrote the status
+ type: string
+ namespace:
+ description: namespace of the pod that wrote the status
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: false
status:
acceptedNames:
kind: ""
diff --git a/manifest_staging/deploy/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml b/manifest_staging/deploy/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml
index 9a3bf5022..c8a5e0a7b 100644
--- a/manifest_staging/deploy/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml
+++ b/manifest_staging/deploy/secrets-store.csi.x-k8s.io_secretproviderclasses.yaml
@@ -1,4 +1,3 @@
-
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
@@ -16,178 +15,203 @@ spec:
singular: secretproviderclass
scope: Namespaced
versions:
- - name: v1
- schema:
- openAPIV3Schema:
- description: SecretProviderClass is the Schema for the secretproviderclasses
- API
- 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
- properties:
- parameters:
- additionalProperties:
+ - name: v1
+ schema:
+ openAPIV3Schema:
+ description:
+ SecretProviderClass is the Schema for the secretproviderclasses
+ API
+ 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
+ properties:
+ parameters:
+ additionalProperties:
+ type: string
+ description: Configuration for specific provider
+ type: object
+ provider:
+ description: Configuration for provider name
type: string
- description: Configuration for specific provider
- type: object
- provider:
- description: Configuration for provider name
- type: string
- secretObjects:
- items:
- description: SecretObject defines the desired state of synced K8s
- secret objects
+ syncOptions:
+ description: SyncOptions defines the secret type when syncing all secrets listed in the parameters field
properties:
- annotations:
- additionalProperties:
- type: string
- description: annotations of k8s secret object
- type: object
- data:
- items:
- description: SecretObjectData defines the desired state of
- synced K8s secret object data
- properties:
- key:
- description: data field to populate
- type: string
- objectName:
- description: name of the object to sync
- type: string
- type: object
- type: array
- labels:
- additionalProperties:
- type: string
- description: labels of K8s secret object
- type: object
- secretName:
- description: name of the K8s secret object
- type: string
+ syncAll:
+ description: SyncAll as true will sync all secrets defined in the parameters field to K8s
+ type: boolean
type:
description: type of K8s secret object
type: string
type: object
- type: array
- type: object
- status:
- description: SecretProviderClassStatus defines the observed state of SecretProviderClass
- properties:
- byPod:
- items:
- description: ByPodStatus defines the state of SecretProviderClass
- as seen by an individual controller
- properties:
- id:
- description: id of the pod that wrote the status
- type: string
- namespace:
- description: namespace of the pod that wrote the status
- type: string
+ secretObjects:
+ items:
+ description:
+ SecretObject defines the desired state of synced K8s
+ secret objects
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ description: annotations of k8s secret object
+ type: object
+ syncAll:
+ description: SyncAll can sync all secrets defined in the parameters field of SecretProviderClass
+ type: boolean
+ data:
+ items:
+ description:
+ SecretObjectData defines the desired state of
+ synced K8s secret object data
+ properties:
+ key:
+ description: data field to populate
+ type: string
+ objectName:
+ description: name of the object to sync
+ type: string
+ type: object
+ type: array
+ labels:
+ additionalProperties:
+ type: string
+ description: labels of K8s secret object
+ type: object
+ secretName:
+ description: name of the K8s secret object
+ type: string
+ type:
+ description: type of K8s secret object
+ type: string
+ type: object
+ type: array
+ type: object
+ status:
+ description: SecretProviderClassStatus defines the observed state of SecretProviderClass
+ properties:
+ byPod:
+ items:
+ description:
+ ByPodStatus defines the state of SecretProviderClass
+ as seen by an individual controller
+ properties:
+ id:
+ description: id of the pod that wrote the status
+ type: string
+ namespace:
+ description: namespace of the pod that wrote the status
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: true
+ - name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description:
+ SecretProviderClass is the Schema for the secretproviderclasses
+ API
+ 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
+ properties:
+ parameters:
+ additionalProperties:
+ type: string
+ description: Configuration for specific provider
type: object
- type: array
- type: object
- type: object
- served: true
- storage: true
- - name: v1alpha1
- schema:
- openAPIV3Schema:
- description: SecretProviderClass is the Schema for the secretproviderclasses
- API
- 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: SecretProviderClassSpec defines the desired state of SecretProviderClass
- properties:
- parameters:
- additionalProperties:
+ provider:
+ description: Configuration for provider name
type: string
- description: Configuration for specific provider
- type: object
- provider:
- description: Configuration for provider name
- type: string
- secretObjects:
- items:
- description: SecretObject defines the desired state of synced K8s
- secret objects
- properties:
- annotations:
- additionalProperties:
- type: string
- description: annotations of k8s secret object
- type: object
- data:
- items:
- description: SecretObjectData defines the desired state of
- synced K8s secret object data
- properties:
- key:
- description: data field to populate
- type: string
- objectName:
- description: name of the object to sync
- type: string
+ secretObjects:
+ items:
+ description:
+ SecretObject defines the desired state of synced K8s
+ secret objects
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ description: annotations of k8s secret object
+ type: object
+ data:
+ items:
+ description:
+ SecretObjectData defines the desired state of
+ synced K8s secret object data
+ properties:
+ key:
+ description: data field to populate
+ type: string
+ objectName:
+ description: name of the object to sync
+ type: string
+ type: object
+ type: array
+ labels:
+ additionalProperties:
+ type: string
+ description: labels of K8s secret object
type: object
- type: array
- labels:
- additionalProperties:
+ secretName:
+ description: name of the K8s secret object
type: string
- description: labels of K8s secret object
- type: object
- secretName:
- description: name of the K8s secret object
- type: string
- type:
- description: type of K8s secret object
- type: string
- type: object
- type: array
- type: object
- status:
- description: SecretProviderClassStatus defines the observed state of SecretProviderClass
- properties:
- byPod:
- items:
- description: ByPodStatus defines the state of SecretProviderClass
- as seen by an individual controller
- properties:
- id:
- description: id of the pod that wrote the status
- type: string
- namespace:
- description: namespace of the pod that wrote the status
- type: string
- type: object
- type: array
- type: object
- type: object
- served: true
- storage: false
+ type:
+ description: type of K8s secret object
+ type: string
+ type: object
+ type: array
+ type: object
+ status:
+ description: SecretProviderClassStatus defines the observed state of SecretProviderClass
+ properties:
+ byPod:
+ items:
+ description:
+ ByPodStatus defines the state of SecretProviderClass
+ as seen by an individual controller
+ properties:
+ id:
+ description: id of the pod that wrote the status
+ type: string
+ namespace:
+ description: namespace of the pod that wrote the status
+ type: string
+ type: object
+ type: array
+ type: object
+ type: object
+ served: true
+ storage: false
status:
acceptedNames:
kind: ""
diff --git a/pkg/rotation/reconciler.go b/pkg/rotation/reconciler.go
index 877058a90..9560e68c9 100644
--- a/pkg/rotation/reconciler.go
+++ b/pkg/rotation/reconciler.go
@@ -34,9 +34,11 @@ import (
"sigs.k8s.io/secrets-store-csi-driver/pkg/util/k8sutil"
"sigs.k8s.io/secrets-store-csi-driver/pkg/util/secretutil"
"sigs.k8s.io/secrets-store-csi-driver/pkg/util/spcpsutil"
+ "sigs.k8s.io/secrets-store-csi-driver/pkg/util/spcutil"
"sigs.k8s.io/secrets-store-csi-driver/pkg/version"
corev1 "k8s.io/api/core/v1"
+ v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@@ -429,7 +431,7 @@ func (r *Reconciler) reconcile(ctx context.Context, spcps *secretsstorev1.Secret
}
}
- if len(spc.Spec.SecretObjects) == 0 {
+ if len(spc.Spec.SecretObjects) == 0 && !spc.Spec.SyncOptions.SyncAll {
klog.InfoS("spc doesn't contain secret objects", "spc", klog.KObj(spc), "pod", klog.KObj(pod), "controller", "rotation")
return nil
}
@@ -438,6 +440,25 @@ func (r *Reconciler) reconcile(ctx context.Context, spcps *secretsstorev1.Secret
r.generateEvent(pod, corev1.EventTypeWarning, k8sSecretRotationFailedReason, fmt.Sprintf("failed to get mounted files, err: %+v", err))
return fmt.Errorf("failed to get mounted files, err: %w", err)
}
+
+ if spc.Spec.SyncOptions.SyncAll {
+ if len(spc.Spec.SecretObjects) == 0 {
+ spc.Spec.SecretObjects = spcutil.BuildSecretObjects(files, secretutil.GetSecretType(strings.TrimSpace(spc.Spec.SyncOptions.Type)))
+ } else {
+ spc.Spec.SecretObjects = append(spc.Spec.SecretObjects, spcutil.BuildSecretObjects(files, secretutil.GetSecretType(strings.TrimSpace(spc.Spec.SyncOptions.Type)))...)
+ }
+ }
+
+ for _, secretObj := range spc.Spec.SecretObjects {
+ if secretObj.SyncAll {
+ if secretutil.GetSecretType(strings.TrimSpace(secretObj.Type)) != v1.SecretTypeOpaque {
+ return fmt.Errorf("secret provider class %s/%s cannot use secretObjects[*].syncAll for non-opaque secrets", spc.Namespace, spc.Name)
+ }
+
+ spcutil.BuildSecretObjectData(files, secretObj)
+ }
+ }
+
for _, secretObj := range spc.Spec.SecretObjects {
secretName := strings.TrimSpace(secretObj.SecretName)
diff --git a/pkg/util/secretutil/secret.go b/pkg/util/secretutil/secret.go
index 29d51c7d3..8b2d78433 100644
--- a/pkg/util/secretutil/secret.go
+++ b/pkg/util/secretutil/secret.go
@@ -38,8 +38,15 @@ const (
privateKeyType = "PRIVATE KEY"
privateKeyTypeRSA = "RSA PRIVATE KEY"
privateKeyTypeEC = "EC PRIVATE KEY"
+ basicAuthUsername = "username"
+ basicAuthPassword = "password"
)
+type basicAuthCreds struct {
+ Username string
+ Password string
+}
+
// getCertPart returns the certificate or the private key part of the cert
func GetCertPart(data []byte, key string) ([]byte, error) {
if key == corev1.TLSPrivateKeyKey {
@@ -121,6 +128,16 @@ func getPrivateKey(data []byte) ([]byte, error) {
return pem.EncodeToMemory(block), nil
}
+// getCredentials parses the mounted content and returns the required
+// key-value pairs for a kubernetes.io/basic-auth K8s secret
+func getCredentials(data []byte) basicAuthCreds {
+ credentials := strings.Split(string(data), ",")
+ return basicAuthCreds{
+ Username: credentials[0],
+ Password: credentials[1],
+ }
+}
+
// GetSecretType returns a k8s secret type.
// Kubernetes doesn't impose any constraints on the type name: https://kubernetes.io/docs/concepts/configuration/secret/#secret-types
// If the secret type is empty, then default is Opaque.
@@ -155,7 +172,7 @@ func GetSecretData(secretObjData []*secretsstorev1.SecretObjectData, secretType
dataKey := strings.TrimSpace(data.Key)
if len(objectName) == 0 {
- return datamap, fmt.Errorf("object name in secretObjects.data")
+ return datamap, fmt.Errorf("object name in secretObjects.data is empty")
}
if len(dataKey) == 0 {
return datamap, fmt.Errorf("key in secretObjects.data is empty")
@@ -176,6 +193,13 @@ func GetSecretData(secretObjData []*secretsstorev1.SecretObjectData, secretType
}
datamap[dataKey] = c
}
+ if secretType == corev1.SecretTypeBasicAuth {
+ credentials := getCredentials(content)
+ delete(datamap, dataKey)
+
+ datamap[basicAuthUsername] = []byte(credentials.Username)
+ datamap[basicAuthPassword] = []byte(credentials.Password)
+ }
}
return datamap, nil
}
diff --git a/pkg/util/spcutil/secret_object_data.go b/pkg/util/spcutil/secret_object_data.go
new file mode 100644
index 000000000..7d875941a
--- /dev/null
+++ b/pkg/util/spcutil/secret_object_data.go
@@ -0,0 +1,186 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+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 spcutil
+
+import (
+ "strings"
+
+ corev1 "k8s.io/api/core/v1"
+ secretsstorev1 "sigs.k8s.io/secrets-store-csi-driver/apis/v1"
+)
+
+const (
+ tlsKey = "tls.key"
+ tlsCert = "tls.crt"
+ dockerConfigJsonKey = ".dockerconfigjson"
+ sshPrivateKey = "ssh-privatekey"
+)
+
+// BuildSecretObjectData builds the .Spec.SecretObjects[*].Data list of a SecretObject when SyncAll is true
+func BuildSecretObjectData(files map[string]string, secretObj *secretsstorev1.SecretObject) {
+
+ for key := range files {
+ var (
+ nested []string
+ renamedKey string
+ )
+
+ nested = strings.Split(key, "/")
+ if len(nested) > 0 {
+ renamedKey = strings.Join(nested, "-")
+ }
+
+ if renamedKey == "" {
+ secretObj.Data = append(secretObj.Data, &secretsstorev1.SecretObjectData{
+ ObjectName: key,
+ Key: key,
+ })
+ continue
+ }
+
+ secretObj.Data = append(secretObj.Data, &secretsstorev1.SecretObjectData{
+ ObjectName: key,
+ Key: renamedKey,
+ })
+ }
+}
+
+// BuildSecretObjects builds the .Spec.SecretObjects list of a SecretProviderClass when .SyncOptions.SyncAll is true
+// How a SecretObject is built is dependent on the type of secret
+func BuildSecretObjects(files map[string]string, secretType corev1.SecretType) []*secretsstorev1.SecretObject {
+ var (
+ secretObject *secretsstorev1.SecretObject
+ secretObjects []*secretsstorev1.SecretObject
+ )
+
+ secretObjects = make([]*secretsstorev1.SecretObject, 0)
+ for key := range files {
+
+ switch secretType {
+ case corev1.SecretTypeOpaque:
+ secretObject = createOpaqueSecretDataObject(key)
+ case corev1.SecretTypeTLS:
+ secretObject = createTLSSecretDataObject(key)
+ case corev1.SecretTypeDockerConfigJson:
+ secretObject = createDockerConfigJsonSecretDataObject(key)
+ case corev1.SecretTypeBasicAuth:
+ secretObject = createBasicAuthSecretDataObject(key)
+ case corev1.SecretTypeSSHAuth:
+ secretObject = createSSHSecretDataObject(key)
+ }
+
+ secretObjects = append(secretObjects, secretObject)
+ }
+
+ return secretObjects
+}
+
+// createOpaqueSecretDataObject creates a SecretObject for an Opaque secret
+func createOpaqueSecretDataObject(key string) *secretsstorev1.SecretObject {
+ return &secretsstorev1.SecretObject{
+ SecretName: setSecretName(key),
+ Type: string(corev1.SecretTypeOpaque),
+ Data: []*secretsstorev1.SecretObjectData{
+ {
+ ObjectName: key,
+ Key: setKey(key),
+ },
+ },
+ }
+}
+
+// createTLSSecretDataObject creates a SecretObject for an TLS secret
+func createTLSSecretDataObject(key string) *secretsstorev1.SecretObject {
+ return &secretsstorev1.SecretObject{
+ SecretName: setSecretName(key),
+ Type: string(corev1.SecretTypeTLS),
+ Data: []*secretsstorev1.SecretObjectData{
+ {
+ ObjectName: key,
+ Key: tlsKey,
+ },
+ {
+ ObjectName: key,
+ Key: tlsCert,
+ },
+ },
+ }
+}
+
+// createDockerConfigJsonSecretDataObject creates a SecretObject for an DockerConfigJSON secret
+func createDockerConfigJsonSecretDataObject(key string) *secretsstorev1.SecretObject {
+ return &secretsstorev1.SecretObject{
+ SecretName: setSecretName(key),
+ Type: string(corev1.SecretTypeDockerConfigJson),
+ Data: []*secretsstorev1.SecretObjectData{
+ {
+ ObjectName: key,
+ Key: dockerConfigJsonKey,
+ },
+ },
+ }
+}
+
+// createBasicAuthSecretDataObject creates a SecretObject for an Basic-Auth secret
+func createBasicAuthSecretDataObject(key string) *secretsstorev1.SecretObject {
+ return &secretsstorev1.SecretObject{
+ SecretName: setSecretName(key),
+ Type: string(corev1.SecretTypeBasicAuth),
+ Data: []*secretsstorev1.SecretObjectData{
+ {
+ ObjectName: key,
+ Key: setKey(key),
+ },
+ },
+ }
+}
+
+// createSSHSecretDataObject creates a SecretObject for an SSH-Auth secret
+func createSSHSecretDataObject(key string) *secretsstorev1.SecretObject {
+ return &secretsstorev1.SecretObject{
+ SecretName: setSecretName(key),
+ Type: string(corev1.SecretTypeSSHAuth),
+ Data: []*secretsstorev1.SecretObjectData{
+ {
+ ObjectName: key,
+ Key: sshPrivateKey,
+ },
+ },
+ }
+}
+
+// setSecretName sets the name of a secret to the value of "objectName" separated by "-"
+func setSecretName(key string) string {
+ nested := strings.Split(key, "/")
+
+ if len(nested) > 0 {
+ return strings.Join(nested, "-")
+ }
+
+ return key
+}
+
+// setKey sets the key of a secret to the name of the mounted file
+func setKey(key string) string {
+ nested := strings.Split(key, "/")
+
+ if len(nested) > 0 {
+ return nested[len(nested)-1]
+ }
+
+ return key
+}
diff --git a/pkg/util/spcutil/secret_object_data_test.go b/pkg/util/spcutil/secret_object_data_test.go
new file mode 100644
index 000000000..a5d0499e6
--- /dev/null
+++ b/pkg/util/spcutil/secret_object_data_test.go
@@ -0,0 +1,374 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+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 spcutil
+
+import (
+ "reflect"
+ "sort"
+ "testing"
+
+ corev1 "k8s.io/api/core/v1"
+ secretsstorev1 "sigs.k8s.io/secrets-store-csi-driver/apis/v1"
+)
+
+const (
+ cert = `
+-----BEGIN CERTIFICATE-----
+MIIDOTCCAiGgAwIBAgIJAP0J5Z7N0Y5fMA0GCSqGSIb3DQEBCwUAMDMxFzAVBgNV
+BAMMDmRlbW8uYXp1cmUuY29tMRgwFgYDVQQKDA9ha3MtaW5ncmVzcy10bHMwHhcN
+MjAwNDE1MDQyMzQ2WhcNMjEwNDE1MDQyMzQ2WjAzMRcwFQYDVQQDDA5kZW1vLmF6
+dXJlLmNvbTEYMBYGA1UECgwPYWtzLWluZ3Jlc3MtdGxzMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAyS3Zky3n8JlLBxPLzgUpKZYxvzRadeWLmWVbK9by
+o08S0Ss8Jao7Ay1wHtnLbn52rzCX6IX1sAe1TAT755Gk7JtLMkshtj6F8BNeelEy
+E1gsBE5ntY5vyLTm/jZUIKz2Z9TLnqvQTmp6gJ68BKJ1NobnsHiAcKc6hI7kmY9C
+oshmAi5qiKYBgzv/thji0093vtVSa9iwHhQp+AEIMhkvM5ZZkiU5eE6MT9SBEcVW
+KmWF28UsB04daYwS2MKJ5l6d4n0LUdAG0FBt1lCoT9rwUDj9l3Mqmi953gw26LUr
+NrYnM/8N2jl7Cuyw5alIWaUDrt5i+pu8wdWfzVk+fO7x8QIDAQABo1AwTjAdBgNV
+HQ4EFgQUwFBbR014McETdrGGklpEQcl71Q0wHwYDVR0jBBgwFoAUwFBbR014McET
+drGGklpEQcl71Q0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEATgTy
+gg1Q6ISSekiBCe12dqUTMFQh9GKpfYWKRbMtjOjpc7Mdwkdmm3Fu6l3RfEFT28Ij
+fy97LMYv8W7beemDFqdmneb2w2ww0ZAFJg+GqIJZ9s/JadiFBDNU7CmJMhA225Qz
+XC8ovejiePslnL4QJWlhVG93ZlBJ6SDkRgfcoIW2x4IBE6wv7jmRF4lOvb3z1ddP
+iPQqhbEEbwMpXmWv7/2RnjAHdjdGaWRMC5+CaI+lqHyj6ir1c+e6u1QUY54qjmgM
+koN/frqYab5Ek3kauj1iqW7rPkrFCqT2evh0YRqb1bFsCLJrRNxnOZ5wKXV/OYQa
+QX5t0wFGCZ0KlbXDiw==
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDJLdmTLefwmUsH
+E8vOBSkpljG/NFp15YuZZVsr1vKjTxLRKzwlqjsDLXAe2ctufnavMJfohfWwB7VM
+BPvnkaTsm0sySyG2PoXwE156UTITWCwETme1jm/ItOb+NlQgrPZn1Mueq9BOanqA
+nrwEonU2hueweIBwpzqEjuSZj0KiyGYCLmqIpgGDO/+2GOLTT3e+1VJr2LAeFCn4
+AQgyGS8zllmSJTl4ToxP1IERxVYqZYXbxSwHTh1pjBLYwonmXp3ifQtR0AbQUG3W
+UKhP2vBQOP2XcyqaL3neDDbotSs2ticz/w3aOXsK7LDlqUhZpQOu3mL6m7zB1Z/N
+WT587vHxAgMBAAECggEAJb0qIYftCJ9ZCbzW8JDbRefc8SdbCN7Er0PqNHEgFy6Q
+MxjPMambZF8ztzXYCaRDk12kQYRPsHPhuJ7+ulQCAjinhIm/izZzXbPkd0GgCSzz
+JOOoZNCRe68j3fBHG9IWbyfmAp/sdalXzaT5VE09e7sW323bekaEnbVIgN30/CAS
+gI77YdaIhG+PT/pSCOc11MTkBJp+VhT1tEtlRAR78b1RXbGi1oUHRee7C3Ia8IKQ
+3L5dPxR9RsYsR2O66908kEi8ZcuIjcbIuRPDXYHY+5Nwm3mXuZlkyjyfxJXsIA8i
+qBrQrSpHGgAn1TVlLDSCKPLbkRzBRRvAW0zL/cDTuQKBgQDq/9Yxx9QivAuUxxdE
+u0VO5CzzZYFWhDxAXS3/wYyo1YnoPtUz/lGCvMWp0k2aaa0+KTXv2fRCUGSujHW7
+Jfo4kuMPkauAhoXx9QJAcjoK0nNbYEaqoJyMoRID+Qb9XHkj+lmBTmMVgALCT9DI
+HekHj/M3b7CknbfWv1sOZ/vpQwKBgQDbKEuP/DWQa9DC5nn5phHD/LWZLG/cMR4X
+TmwM/cbfRxM/6W0+/KLAodz4amGRzVlW6ax4k26BSE8Zt/SiyA1DQRTeFloduoqW
+iWF4dMeItxw2am+xLREwtoN3FgsJHu2z/O/0aaBAOMLUXIPIyiE4L6OnEPifE/pb
+AM8EbM5auwKBgGhdABIRjbtzSa1kEYhbprcXjIL3lE4I4f0vpIsNuNsOInW62dKC
+Yk6uaRY3KHGn9uFBSgvf/qMost310R8xCYPwb9htN/4XQAspZTubvv0pY0O0aQ3D
+0GJ/8dFD2f/Q/pekyfUsC8Lzm8YRzkXhSqkqG7iF6Kviw08iolyuf2ijAoGBANaA
+pRzDvWWisUziKsa3zbGnGdNXVBEPniUvo8A/b7RAK84lWcEJov6qLs6RyPfdJrFT
+u3S00LcHICzLCU1+QsTt4U/STtfEKjtXMailnFrq5lk4aiPfOXEVYq1fTOPbesrt
+Katu6uOQ6tjRyEbx1/vXXPV7Peztr9/8daMeIAdbAoGBAOYRJ1CzMYQKjWF32Uas
+7hhQxyH1QI4nV56Dryq7l/UWun2pfwNLZFqOHD3qm05aznzNKvk9aHAsOPFfUUXO
+7sp0Ge5FLMSw1uMNnutcVcMz37KAY2fOoE2xoLM4DU/H2NqDjeGCsOsU1ReRS1vB
+J+42JGwBdLV99ruYKVKOWPh4
+-----END PRIVATE KEY-----
+`
+
+ sshKey = `
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBa+0SeK0
+uw8TTDVmQuIbT+AAAAEAAAAAEAAAGXAAAAB3NzaC1yc2EAAAADAQABAAABgQCrAMIhG+1R
+tG5kgrmieNDE+hjblN64keV0EnsaSpCKCBFFnWQGCOaNZaoIJVX088IFCzTkz0QeLHl7qO
+cSeBDxdm/GTvphEyh5JTroV+ipDq6+6tJ2YNLksP+NmMW5/A3/byFK7cSglwupJgBdMX7l
+oAFZLMCOBiLC4CTHmA74xRHkwHgdNZUiiUzw0eC1fUOoQWKT6W+rsCV/Tk6hh0X7x+qLO8
+GnT8S2GzapMY0HoJTK5yV4m/0KV/Ky90OfTDZnAAHEYjQYvQ2YY0UEcU6KZ71msZZ2XCPY
+p1mVpMXJ9b2KCOOMKm8ursla79plYmH6cUaAsonT182rD0lHIZPHFxcRZpZGs5Zp/iyZ41
+MK4vlKwEMRdn9KjByTaS21fOHDO3De9LUwg4Q0DmsUrp8M0lG8BX4fJl51v5TCYh2+X2ds
+RIsJenJ24Dmuv5tQrWmr6JMxu3xccUHN/NBMYGESEXjMWKAtSfssARbVI8QRJn21N/838C
+JV57cv5l7dI7EAAAWQB3gJeXmZjEBVrHOM77c4bXqlhm55jWwMj79N/jc6lGGmESArjbfY
+g85wYR0LEsiXETTnkwpCmCRAuUKj5+vAGyDeWM76KGp4igl8RExF8bv74RFUyN3A7O2EbM
+HQ2xYoL4W1KX67AT5KJD3g+4nkV74DWhdlazA2DspL7jSz6yDfDXeYxsxIozvkEhoac3T7
+u1UbfvDZw7MnW95gc3ybm74DH1nso2TQzvHEN9Vq/hXa50e7lJtXJ1nVfIBxda0VNqCAdo
+CnTG5Q5UKc2l4dfhqScCwbBWjO2M2YPYMBOUSayigQ6S1sJCYL3TpGUl290Q1cWFWQ+ORl
+EfeGe9TKxnY64smQH2LftuO5WDmwvf1Ske5BATtZX6zOUpwjgAQ1Bpj0wpht54O8Rbo8ub
+kmh+uaE6k0iUEN2van3Mkq9ok/62J+QeFbK7V+Ag2+l4MI7f5cbfcwyMRyLaLIPvTfQWPQ
+3RtQdbQHdcGvfmu6aPkKhN5/uoyBbmWOvIsnlYiZp4oY15CFtIYIyhyaHTm1/2rZnuyC6q
+Q6dlWxkZEF6p7Uh7dB+9x/GR+MfCLiFNuYms//r1ZEtYp2ctIgL4W2z09a2xN9jJ4Ij3Kn
+amJ/NUen5EiTEdNwZlAtpwfh6/x7eQnbq3bMmJcFdrt27lHQg6k2NOKsDxEoAEn5q3fySH
+XRT848yHyDXhCht0AooeFk/ToyzjSWlRTPjgJZ+ryckwqOB/D4UvQH5r5SWhQtTfzGUoO7
+9Ozmj4CiCMtlrdcDiQTbgyR1BPReyoR5Xq+m+S2i0kFzGedTalFxhrhHCoSiuy4YcKCcVd
++xQuuJ7HrEkY78EMoII/Al8TKTyD6FWQGWoqWEVcwBXV4J3KUkk1N3oEaqQwj/TXpGlzUf
+17QvEjDepHlCbI/5KBUCl8gzc3ByisRWx6a67VbOOih61304VUHapcAJmduiOBnnSFj2kb
+3BwANN5uk+lzbeyWF83VthZXr2WcWDqE/g1Ox87TkBHE8JePlxc3/bPkeD8feC11YmNJzX
+91kU2XPOxplD11fCCpIh2tbjRUR1VVpoVuf75FwsUo3ecqSSJ8MbpQduGKCllpBuvo2yLQ
+A9Bn836/bEvzbpQhTPrPCC7/Nk9QL+PtgfROcW2uOHiMrNZrAyghboV4KPPtmB9RWCxqoY
+viWQMn4wIShrg1qluZBpKrNUr7NedjU7MjY6FMK9nernY4YllQB77/MkJNm74Gu8meRGSn
+cGQA3P/xcQXR3QQ6spXTfARUSoDF0eNALhoEKwhFcPGNc8nI1g2Ach/Px567aKuOuThOPT
+2Ue5/pe4YzMHKOiStLMgbYD31k9KKjvqNbLV1DJFHb7fPymY3GhfrtxemyX1jbZFxUfiKr
+WrUuOa/Vzi1fkrTdC62TGHKlWmQD8dUuuuioTbWyAAmPODcsjurXxQVzTJqO8bwrQGKjEc
+E/UPV31EMHWlYOQ35lKYMkxyWXeHA9UhGaC3ns+TMzeRRgbX7LRjhwPo4y1gUo4wEjrqyd
+PpLSGRRtq8JVFonxnf5xttHJegXKhVb2VkEquZ2jL3GcQyCh6oaKo0yNIdOuQhI1aA3oxZ
+f+Eag3u3IzfZYCBnXsRfZ3j9+L+VmTz4WJx6iRHSQRPrSBzVi3U0I5N+ohxzyhORWr2tpp
+jcYZ59Pzboy7FXp5s4JK0TOP+XCK9h6v5T7V5fW6XS5fABiVl94zVc1THnJnmHhBIc+7Dm
+hlUYwT+6TWxDOJo8sqp6+NLLTx2UxOqKUWWCUCSvap2ptOvIZRm2Cq5kW3W2FFo7tSftWt
+d9H7wnDSuC4Zv1ze8Wo2TbXv222TIysd8rK4j+0dTDibvZ1WVbFs00cEBXKIZxskrSlAIb
+C9I7vbQHcdYGWqof7MBPsMcaJ+0=
+-----END OPENSSH PRIVATE KEY-----
+
+`
+
+ dockerconfigjson = "{\"auths\":{\"https://index.docker.io/v1/\":{\"username\":\"user1\",\"password\":\"password1\",\"email\":\"account1@email.com\",\"auth\":\"dXNlcjE6cGFzc3dvcmQx\"}}}"
+)
+
+func TestBuildSecretObjectData(t *testing.T) {
+ files := map[string]string{
+ "username": "test user",
+ "password": "test password",
+ "nested/username": "test nested user",
+ "nested/double/username": "double nested user",
+ }
+
+ secretObj := &secretsstorev1.SecretObject{
+ SecretName: "test-secret",
+ Type: "Opaque",
+ SyncAll: true,
+ }
+
+ BuildSecretObjectData(files, secretObj)
+
+ expected := &secretsstorev1.SecretObject{
+ SecretName: "test-secret",
+ Type: "Opaque",
+ SyncAll: true,
+ Data: []*secretsstorev1.SecretObjectData{
+ {
+ ObjectName: "username",
+ Key: "username",
+ },
+ {
+ ObjectName: "password",
+ Key: "password",
+ },
+ {
+ ObjectName: "nested/username",
+ Key: "nested-username",
+ },
+ {
+ ObjectName: "nested/double/username",
+ Key: "nested-double-username",
+ },
+ },
+ }
+
+ if ok := assertSecretsObjectsEqual(expected, secretObj); !ok {
+ t.Fatal("secret objects did not match")
+ }
+}
+
+func TestBuildSecretObjects(t *testing.T) {
+ tests := []struct {
+ files map[string]string
+ secretType corev1.SecretType
+ expected []*secretsstorev1.SecretObject
+ }{
+ {
+ files: map[string]string{
+ "username": "test user",
+ "password": "test password",
+ "nested/username": "test nested user",
+ "nested/double/username": "double nested user",
+ },
+ secretType: corev1.SecretTypeOpaque,
+ expected: []*secretsstorev1.SecretObject{
+ {
+ SecretName: "username",
+ Type: string(corev1.SecretTypeOpaque),
+ Data: []*secretsstorev1.SecretObjectData{
+ {
+ ObjectName: "username",
+ Key: "username",
+ },
+ },
+ },
+ {
+ SecretName: "password",
+ Type: string(corev1.SecretTypeOpaque),
+ Data: []*secretsstorev1.SecretObjectData{
+ {
+ ObjectName: "password",
+ Key: "password",
+ },
+ },
+ },
+ {
+ SecretName: "nested-username",
+ Type: string(corev1.SecretTypeOpaque),
+ Data: []*secretsstorev1.SecretObjectData{
+ {
+ ObjectName: "nested/username",
+ Key: "username",
+ },
+ },
+ },
+ {
+ SecretName: "nested-double-username",
+ Type: string(corev1.SecretTypeOpaque),
+ Data: []*secretsstorev1.SecretObjectData{
+ {
+ ObjectName: "nested/double/username",
+ Key: "username",
+ },
+ },
+ },
+ },
+ }, {
+ files: map[string]string{
+ "cert": cert,
+ },
+ secretType: corev1.SecretTypeTLS,
+ expected: []*secretsstorev1.SecretObject{
+ {
+ SecretName: "cert",
+ Type: string(corev1.SecretTypeTLS),
+ Data: []*secretsstorev1.SecretObjectData{
+ {
+ ObjectName: "cert",
+ Key: "tls.key",
+ },
+ {
+ ObjectName: "cert",
+ Key: "tls.crt",
+ },
+ },
+ },
+ },
+ }, {
+ files: map[string]string{
+ "basic/basic1": "my-username1,my-password1",
+ "basic/basic2": "my-username2,my-password2",
+ "basic/basic3": "my-username3,my-password3",
+ },
+ secretType: corev1.SecretTypeBasicAuth,
+ expected: []*secretsstorev1.SecretObject{
+ {
+ SecretName: "basic-basic1",
+ Type: string(corev1.SecretTypeBasicAuth),
+ Data: []*secretsstorev1.SecretObjectData{
+ {
+ ObjectName: "basic/basic1",
+ Key: "basic1",
+ },
+ },
+ },
+ {
+ SecretName: "basic-basic2",
+ Type: string(corev1.SecretTypeBasicAuth),
+ Data: []*secretsstorev1.SecretObjectData{
+ {
+ ObjectName: "basic/basic2",
+ Key: "basic2",
+ },
+ },
+ },
+ {
+ SecretName: "basic-basic3",
+ Type: string(corev1.SecretTypeBasicAuth),
+ Data: []*secretsstorev1.SecretObjectData{
+ {
+ ObjectName: "basic/basic3",
+ Key: "basic3",
+ },
+ },
+ },
+ },
+ }, {
+ files: map[string]string{
+ "ssh": sshKey,
+ },
+ secretType: corev1.SecretTypeSSHAuth,
+ expected: []*secretsstorev1.SecretObject{
+ {
+ SecretName: "ssh",
+ Type: string(corev1.SecretTypeSSHAuth),
+ Data: []*secretsstorev1.SecretObjectData{
+ {
+ ObjectName: "ssh",
+ Key: "ssh-privatekey",
+ },
+ },
+ },
+ },
+ },
+ {
+ files: map[string]string{
+ "dev/docker": dockerconfigjson,
+ },
+ secretType: corev1.SecretTypeDockerConfigJson,
+ expected: []*secretsstorev1.SecretObject{
+ {
+ SecretName: "dev-docker",
+ Type: string(corev1.SecretTypeDockerConfigJson),
+ Data: []*secretsstorev1.SecretObjectData{
+ {
+ ObjectName: "dev/docker",
+ Key: ".dockerconfigjson",
+ },
+ },
+ },
+ },
+ },
+ }
+
+ for _, test := range tests {
+ actualSecretObjects := BuildSecretObjects(test.files, test.secretType)
+ if ok := assertSecretObjectSlicesEqual(test.expected, actualSecretObjects); !ok {
+ t.Fatal("secret object slices did not match")
+ }
+ }
+
+}
+
+func assertSecretsObjectsEqual(expected, actual *secretsstorev1.SecretObject) bool {
+ if expected.SecretName != actual.SecretName {
+ return false
+ }
+
+ if expected.Type != actual.Type {
+ return false
+ }
+
+ sort.Slice(expected.Data, func(i, j int) bool {
+ return expected.Data[i].ObjectName < expected.Data[j].ObjectName
+ })
+
+ sort.Slice(actual.Data, func(i, j int) bool {
+ return actual.Data[i].ObjectName < actual.Data[j].ObjectName
+ })
+
+ return reflect.DeepEqual(expected.Data, actual.Data)
+}
+
+func assertSecretObjectSlicesEqual(expected, actual []*secretsstorev1.SecretObject) bool {
+ if len(expected) != len(actual) {
+ return false
+ }
+
+ sort.Slice(expected, func(i, j int) bool {
+ return expected[i].SecretName < expected[j].SecretName
+ })
+
+ sort.Slice(actual, func(i, j int) bool {
+ return actual[i].SecretName < actual[j].SecretName
+ })
+
+ for i := 0; i < len(expected); i++ {
+ if ok := assertSecretsObjectsEqual(expected[i], actual[i]); !ok {
+ return false
+ }
+ }
+
+ return true
+}
diff --git a/test/bats/e2e-provider.bats b/test/bats/e2e-provider.bats
index ca3834a73..35654ecd4 100644
--- a/test/bats/e2e-provider.bats
+++ b/test/bats/e2e-provider.bats
@@ -112,6 +112,15 @@ export API_VERSION=$(get_secrets_store_api_version)
wait_for_process $WAIT_TIME $SLEEP_TIME "$cmd"
}
+@test "deploy e2e-provider-sync-all v1 secretproviderclass crd" {
+ envsubst < $BATS_TESTS_DIR/e2e_provider_sync_allk8s_v1_secretproviderclass.yaml | kubectl apply -f -
+
+ kubectl wait --for condition=established --timeout=60s crd/secretproviderclasses.secrets-store.csi.x-k8s.io
+
+ cmd="kubectl get secretproviderclasses.secrets-store.csi.x-k8s.io/e2e-provider-sync-all -o yaml | grep e2e-provider-sync-all"
+ wait_for_process $WAIT_TIME $SLEEP_TIME "$cmd"
+}
+
@test "CSI inline volume test with pod portability" {
envsubst < $BATS_TESTS_DIR/pod-secrets-store-inline-volume-crd.yaml | kubectl apply -f -
@@ -170,21 +179,44 @@ export API_VERSION=$(get_secrets_store_api_version)
kubectl wait --for=condition=Ready --timeout=90s pod -l app=busybox
}
+@test "Sync all with K8s secrets - create deployment" {
+ envsubst < $BATS_TESTS_DIR/e2e_provider_sync_allk8s_v1_secretproviderclass.yaml | kubectl apply -f -
+
+ kubectl wait --for condition=established --timeout=60s crd/secretproviderclasses.secrets-store.csi.x-k8s.io
+
+ cmd="kubectl get secretproviderclasses.secrets-store.csi.x-k8s.io/e2e-provider-sync-all -o yaml | grep e2e-provider-sync-all"
+ wait_for_process $WAIT_TIME $SLEEP_TIME "$cmd"
+
+ envsubst < $BATS_TESTS_DIR/deployment-sync_allk8s-e2e-provider-sync-all.yaml | kubectl apply -f -
+
+ kubectl wait --for=condition=Ready --timeout=90s pod -l app=busybox-sync-all
+}
+
@test "Sync with K8s secrets - read secret from pod, read K8s secret, read env var, check secret ownerReferences with multiple owners" {
POD=$(kubectl get pod -l app=busybox -o jsonpath="{.items[0].metadata.name}")
+ SYNC_ALL_POD=$(kubectl get pod -l app=busybox-sync-all -o jsonpath="{.items[0].metadata.name}")
result=$(kubectl exec $POD -- cat /mnt/secrets-store/$SECRET_NAME)
[[ "${result//$'\r'}" == "${SECRET_VALUE}" ]]
+ result=$(kubectl exec $SYNC_ALL_POD -- cat /mnt/secrets-store/$SECRET_NAME)
+ [[ "${result//$'\r'}" == "${SECRET_VALUE}" ]]
+
result=$(kubectl exec $POD -- cat /mnt/secrets-store/$KEY_NAME)
result_base64_encoded=$(echo "${result//$'\r'}" | base64 ${BASE64_FLAGS})
[[ "${result_base64_encoded}" == *"${KEY_VALUE_CONTAINS}"* ]]
+ result=$(kubectl exec $SYNC_ALL_POD -- cat /mnt/secrets-store/$KEY_NAME)
+ result_base64_encoded=$(echo "${result//$'\r'}" | base64 ${BASE64_FLAGS})
+ [[ "${result_base64_encoded}" == *"${KEY_VALUE_CONTAINS}"* ]]
+
result=$(kubectl get secret foosecret -o jsonpath="{.data.username}" | base64 -d)
[[ "${result//$'\r'}" == "${SECRET_VALUE}" ]]
result=$(kubectl exec $POD -- printenv | grep SECRET_USERNAME) | awk -F"=" '{ print $2}'
[[ "${result//$'\r'}" == "${SECRET_VALUE}" ]]
+ result=$(kubectl exec $SYNC_ALL_POD -- printenv | grep SECRET_USERNAME) | awk -F"=" '{ print $2}'
+ [[ "${result//$'\r'}" == "${SECRET_VALUE}" ]]
result=$(kubectl get secret foosecret -o jsonpath="{.metadata.labels.environment}")
[[ "${result//$'\r'}" == "${LABEL_VALUE}" ]]
@@ -192,7 +224,7 @@ export API_VERSION=$(get_secrets_store_api_version)
result=$(kubectl get secret foosecret -o jsonpath="{.metadata.labels.secrets-store\.csi\.k8s\.io/managed}")
[[ "${result//$'\r'}" == "true" ]]
- run wait_for_process $WAIT_TIME $SLEEP_TIME "compare_owner_count foosecret default 2"
+ run wait_for_process $WAIT_TIME $SLEEP_TIME "compare_owner_count foosecret default 3"
assert_success
}
@@ -204,16 +236,23 @@ export API_VERSION=$(get_secrets_store_api_version)
run kubectl delete -f $BATS_TESTS_DIR/deployment-synck8s-e2e-provider.yaml
assert_success
- run wait_for_process $WAIT_TIME $SLEEP_TIME "compare_owner_count foosecret default 1"
+ run wait_for_process $WAIT_TIME $SLEEP_TIME "compare_owner_count foosecret default 2"
assert_success
run kubectl delete -f $BATS_TESTS_DIR/deployment-two-synck8s-e2e-provider.yaml
assert_success
+ run wait_for_process $WAIT_TIME $SLEEP_TIME "compare_owner_count foosecret default 1"
+ assert_success
+
+ run kubectl delete -f $BATS_TESTS_DIR/deployment-sync_allk8s-e2e-provider-sync-all.yaml
+ assert_success
+
run wait_for_process $WAIT_TIME $SLEEP_TIME "check_secret_deleted foosecret default"
assert_success
envsubst < $BATS_TESTS_DIR/e2e_provider_synck8s_v1_secretproviderclass.yaml | kubectl delete -f -
+ envsubst < $BATS_TESTS_DIR/e2e_provider_sync_allk8s_v1_secretproviderclass.yaml | kubectl delete -f -
}
@test "Test Namespaced scope SecretProviderClass - create deployment" {
diff --git a/test/bats/tests/e2e_provider/deployment-sync_allk8s-e2e-provider-sync-all.yaml b/test/bats/tests/e2e_provider/deployment-sync_allk8s-e2e-provider-sync-all.yaml
new file mode 100644
index 000000000..1b134dd4c
--- /dev/null
+++ b/test/bats/tests/e2e_provider/deployment-sync_allk8s-e2e-provider-sync-all.yaml
@@ -0,0 +1,41 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: busybox-deployment-sync-all
+ labels:
+ app: busybox-sync-all
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: busybox-sync-all
+ template:
+ metadata:
+ labels:
+ app: busybox-sync-all
+ spec:
+ terminationGracePeriodSeconds: 0
+ containers:
+ - image: k8s.gcr.io/e2e-test-images/busybox:1.29
+ name: busybox
+ imagePullPolicy: IfNotPresent
+ command:
+ - "/bin/sleep"
+ - "10000"
+ env:
+ - name: SECRET_USERNAME
+ valueFrom:
+ secretKeyRef:
+ name: foosecret
+ key: username
+ volumeMounts:
+ - name: secrets-store-inline
+ mountPath: "/mnt/secrets-store"
+ readOnly: true
+ volumes:
+ - name: secrets-store-inline
+ csi:
+ driver: secrets-store.csi.k8s.io
+ readOnly: true
+ volumeAttributes:
+ secretProviderClass: "e2e-provider-sync-all"
diff --git a/test/bats/tests/e2e_provider/e2e_provider_sync_allk8s_v1_secretproviderclass.yaml b/test/bats/tests/e2e_provider/e2e_provider_sync_allk8s_v1_secretproviderclass.yaml
new file mode 100644
index 000000000..648c809dd
--- /dev/null
+++ b/test/bats/tests/e2e_provider/e2e_provider_sync_allk8s_v1_secretproviderclass.yaml
@@ -0,0 +1,26 @@
+apiVersion: secrets-store.csi.x-k8s.io/v1
+kind: SecretProviderClass
+metadata:
+ name: e2e-provider-sync-all
+spec:
+ provider: e2e-provider
+ secretObjects:
+ - secretName: foosecret
+ type: Opaque
+ labels:
+ environment: "test"
+ data:
+ - objectName: $SECRET_NAME
+ key: username
+ parameters:
+ objects: |
+ array:
+ - |
+ objectName: $SECRET_NAME
+ objectVersion: $SECRET_VERSION
+ - |
+ objectName: $KEY_NAME
+ objectVersion: $KEY_VERSION
+ syncOptions:
+ type: Opaque
+ syncAll: true
diff --git a/test/bats/tests/e2e_provider/e2e_provider_v1_multiple_secretproviderclass.yaml b/test/bats/tests/e2e_provider/e2e_provider_v1_multiple_secretproviderclass.yaml
index eb8b171ca..0d720ffb5 100644
--- a/test/bats/tests/e2e_provider/e2e_provider_v1_multiple_secretproviderclass.yaml
+++ b/test/bats/tests/e2e_provider/e2e_provider_v1_multiple_secretproviderclass.yaml
@@ -5,11 +5,11 @@ metadata:
spec:
provider: e2e-provider
secretObjects:
- - secretName: foosecret-0
- type: Opaque
- data:
- - objectName: $SECRET_NAME
- key: username
+ - secretName: foosecret-0
+ type: Opaque
+ data:
+ - objectName: $SECRET_NAME
+ key: username
parameters:
objects: |
array:
@@ -27,11 +27,11 @@ metadata:
spec:
provider: e2e-provider
secretObjects:
- - secretName: foosecret-1
- type: Opaque
- data:
- - objectName: $SECRET_NAME
- key: username
+ - secretName: foosecret-1
+ type: Opaque
+ data:
+ - objectName: $SECRET_NAME
+ key: username
parameters:
objects: |
array: