mirror of
https://github.com/external-secrets/external-secrets.git
synced 2024-12-14 11:57:59 +00:00
feat: implement provider interface
adds the provider interface, generic store and schema registration. mostly taken from itscontained/secret-manager Co-authored-by: Moritz Johner <beller.moritz@googlemail.com>
This commit is contained in:
parent
ffd4a220d1
commit
f1fb6cfa06
17 changed files with 725 additions and 257 deletions
52
api/v1alpha1/generic_store.go
Normal file
52
api/v1alpha1/generic_store.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=false
|
||||||
|
// +kubebuilder:object:generate:false
|
||||||
|
// +k8s:deepcopy-gen:interfaces=nil
|
||||||
|
// +k8s:deepcopy-gen=nil
|
||||||
|
|
||||||
|
// GenericStore is a common interface for interacting with ClusterSecretStore
|
||||||
|
// or a namespaced SecretStore
|
||||||
|
type GenericStore interface {
|
||||||
|
runtime.Object
|
||||||
|
metav1.Object
|
||||||
|
GetProvider() *SecretStoreProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root:false
|
||||||
|
// +kubebuilder:object:generate:false
|
||||||
|
var _ GenericStore = &SecretStore{}
|
||||||
|
|
||||||
|
// GetProvider returns the underlying provider
|
||||||
|
func (c *SecretStore) GetProvider() *SecretStoreProvider {
|
||||||
|
return c.Spec.Provider
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetProvider sets the underlying provider
|
||||||
|
func (c *SecretStore) SetProvider(provider SecretStoreProvider) {
|
||||||
|
c.Spec.Provider = &provider
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy returns a DeepCopy of the Store
|
||||||
|
func (c *SecretStore) Copy() GenericStore {
|
||||||
|
return c.DeepCopy()
|
||||||
|
}
|
|
@ -18,6 +18,8 @@ limitations under the License.
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/scheme"
|
"sigs.k8s.io/controller-runtime/pkg/scheme"
|
||||||
)
|
)
|
||||||
|
@ -32,3 +34,9 @@ var (
|
||||||
// AddToScheme adds the types in this group-version to the given scheme.
|
// AddToScheme adds the types in this group-version to the given scheme.
|
||||||
AddToScheme = SchemeBuilder.AddToScheme
|
AddToScheme = SchemeBuilder.AddToScheme
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SecretStore type metadata.
|
||||||
|
var (
|
||||||
|
SecretStoreKind = reflect.TypeOf(SecretStore{}).Name()
|
||||||
|
SecretStoreKindAPIVersion = SecretStoreKind + "." + GroupVersion.String()
|
||||||
|
)
|
||||||
|
|
|
@ -34,6 +34,14 @@ type SecretStoreSpec struct {
|
||||||
// +optional
|
// +optional
|
||||||
Controller string `json:"controller"`
|
Controller string `json:"controller"`
|
||||||
|
|
||||||
|
// Used to configure the provider. Only one provider may be set
|
||||||
|
Provider *SecretStoreProvider `json:"provider"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecretStoreProvider contains the provider-specific configration
|
||||||
|
// +kubebuilder:validation:MinProperties=1
|
||||||
|
// +kubebuilder:validation:MaxProperties=1
|
||||||
|
type SecretStoreProvider struct {
|
||||||
// AWSSM configures this store to sync secrets using AWS Secret Manager provider
|
// AWSSM configures this store to sync secrets using AWS Secret Manager provider
|
||||||
// +optional
|
// +optional
|
||||||
AWSSM *AWSSMProvider `json:"awssm,omitempty"`
|
AWSSM *AWSSMProvider `json:"awssm,omitempty"`
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
// +build !ignore_autogenerated
|
// +build !ignore_autogenerated
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
You may obtain a copy of the License at
|
You may obtain a copy of the License at
|
||||||
|
@ -21,7 +19,7 @@ limitations under the License.
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
@ -368,6 +366,26 @@ func (in *SecretStoreList) DeepCopyObject() runtime.Object {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *SecretStoreProvider) DeepCopyInto(out *SecretStoreProvider) {
|
||||||
|
*out = *in
|
||||||
|
if in.AWSSM != nil {
|
||||||
|
in, out := &in.AWSSM, &out.AWSSM
|
||||||
|
*out = new(AWSSMProvider)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretStoreProvider.
|
||||||
|
func (in *SecretStoreProvider) DeepCopy() *SecretStoreProvider {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(SecretStoreProvider)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *SecretStoreRef) DeepCopyInto(out *SecretStoreRef) {
|
func (in *SecretStoreRef) DeepCopyInto(out *SecretStoreRef) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -386,9 +404,9 @@ func (in *SecretStoreRef) DeepCopy() *SecretStoreRef {
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *SecretStoreSpec) DeepCopyInto(out *SecretStoreSpec) {
|
func (in *SecretStoreSpec) DeepCopyInto(out *SecretStoreSpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.AWSSM != nil {
|
if in.Provider != nil {
|
||||||
in, out := &in.AWSSM, &out.AWSSM
|
in, out := &in.Provider, &out.Provider
|
||||||
*out = new(AWSSMProvider)
|
*out = new(SecretStoreProvider)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: apiextensions.k8s.io/v1beta1
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.2.5
|
controller-gen.kubebuilder.io/version: v0.4.1
|
||||||
creationTimestamp: null
|
creationTimestamp: null
|
||||||
name: externalsecrets.external-secrets.io
|
name: externalsecrets.external-secrets.io
|
||||||
spec:
|
spec:
|
||||||
|
@ -15,7 +15,9 @@ spec:
|
||||||
plural: externalsecrets
|
plural: externalsecrets
|
||||||
singular: externalsecret
|
singular: externalsecret
|
||||||
scope: Namespaced
|
scope: Namespaced
|
||||||
validation:
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
schema:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
description: ExternalSecret is the Schema for the externalsecrets API
|
description: ExternalSecret is the Schema for the externalsecrets API
|
||||||
properties:
|
properties:
|
||||||
|
@ -68,8 +70,8 @@ spec:
|
||||||
type: array
|
type: array
|
||||||
dataFrom:
|
dataFrom:
|
||||||
description: DataFrom is used to fetch all properties from a specific
|
description: DataFrom is used to fetch all properties from a specific
|
||||||
Provider data If multiple entries are specified, the Secret keys are
|
Provider data If multiple entries are specified, the Secret keys
|
||||||
merged in the specified order
|
are merged in the specified order
|
||||||
items:
|
items:
|
||||||
description: ExternalSecretDataRemoteRef defines Provider data location
|
description: ExternalSecretDataRemoteRef defines Provider data location
|
||||||
properties:
|
properties:
|
||||||
|
@ -90,17 +92,18 @@ spec:
|
||||||
type: array
|
type: array
|
||||||
refreshInterval:
|
refreshInterval:
|
||||||
description: 'RefreshInterval is the amount of time before the values
|
description: 'RefreshInterval is the amount of time before the values
|
||||||
reading again from the SecretStore provider Valid time units are "ns",
|
reading again from the SecretStore provider Valid time units are
|
||||||
"us" (or "µs"), "ms", "s", "m", "h" (from time.ParseDuration) May
|
"ns", "us" (or "µs"), "ms", "s", "m", "h" (from time.ParseDuration)
|
||||||
be set to zero to fetch and create it once TODO: Default to some value?'
|
May be set to zero to fetch and create it once TODO: Default to
|
||||||
|
some value?'
|
||||||
type: string
|
type: string
|
||||||
secretStoreRef:
|
secretStoreRef:
|
||||||
description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret
|
description: SecretStoreRef defines which SecretStore to fetch the
|
||||||
data
|
ExternalSecret data
|
||||||
properties:
|
properties:
|
||||||
kind:
|
kind:
|
||||||
description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
|
description: Kind of the SecretStore resource (SecretStore or
|
||||||
Defaults to `SecretStore`
|
ClusterSecretStore) Defaults to `SecretStore`
|
||||||
type: string
|
type: string
|
||||||
name:
|
name:
|
||||||
description: Name of the SecretStore resource
|
description: Name of the SecretStore resource
|
||||||
|
@ -109,12 +112,12 @@ spec:
|
||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
target:
|
target:
|
||||||
description: ExternalSecretTarget defines the Kubernetes Secret to be
|
description: ExternalSecretTarget defines the Kubernetes Secret to
|
||||||
created There can be only one target per ExternalSecret
|
be created There can be only one target per ExternalSecret
|
||||||
properties:
|
properties:
|
||||||
creationPolicy:
|
creationPolicy:
|
||||||
description: CreationPolicy defines rules on how to create the resulting
|
description: CreationPolicy defines rules on how to create the
|
||||||
Secret Defaults to 'Owner'
|
resulting Secret Defaults to 'Owner'
|
||||||
type: string
|
type: string
|
||||||
name:
|
name:
|
||||||
description: Name defines the name of the Secret resource to be
|
description: Name defines the name of the Secret resource to be
|
||||||
|
@ -156,9 +159,6 @@ spec:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
version: v1alpha1
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
served: true
|
||||||
storage: true
|
storage: true
|
||||||
status:
|
status:
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: apiextensions.k8s.io/v1beta1
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
controller-gen.kubebuilder.io/version: v0.2.5
|
controller-gen.kubebuilder.io/version: v0.4.1
|
||||||
creationTimestamp: null
|
creationTimestamp: null
|
||||||
name: secretstores.external-secrets.io
|
name: secretstores.external-secrets.io
|
||||||
spec:
|
spec:
|
||||||
|
@ -15,7 +15,9 @@ spec:
|
||||||
plural: secretstores
|
plural: secretstores
|
||||||
singular: secretstore
|
singular: secretstore
|
||||||
scope: Namespaced
|
scope: Namespaced
|
||||||
validation:
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
schema:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
description: SecretStore is the Schema for the secretstores API
|
description: SecretStore is the Schema for the secretstores API
|
||||||
properties:
|
properties:
|
||||||
|
@ -33,10 +35,21 @@ spec:
|
||||||
type: object
|
type: object
|
||||||
spec:
|
spec:
|
||||||
description: SecretStoreSpec defines the desired state of SecretStore
|
description: SecretStoreSpec defines the desired state of SecretStore
|
||||||
|
properties:
|
||||||
|
controller:
|
||||||
|
description: 'Used to select the correct KES controller (think: ingress.ingressClassName)
|
||||||
|
The KES controller is instantiated with a specific controller name
|
||||||
|
and filters ES based on this property'
|
||||||
|
type: string
|
||||||
|
provider:
|
||||||
|
description: Used to configure the provider. Only one provider may
|
||||||
|
be set
|
||||||
|
maxProperties: 1
|
||||||
|
minProperties: 1
|
||||||
properties:
|
properties:
|
||||||
awssm:
|
awssm:
|
||||||
description: AWSSM configures this store to sync secrets using AWS Secret
|
description: AWSSM configures this store to sync secrets using
|
||||||
Manager provider
|
AWS Secret Manager provider
|
||||||
properties:
|
properties:
|
||||||
auth:
|
auth:
|
||||||
description: Auth defines the information necessary to authenticate
|
description: Auth defines the information necessary to authenticate
|
||||||
|
@ -85,11 +98,9 @@ spec:
|
||||||
- auth
|
- auth
|
||||||
- region
|
- region
|
||||||
type: object
|
type: object
|
||||||
controller:
|
type: object
|
||||||
description: 'Used to select the correct KES controller (think: ingress.ingressClassName)
|
required:
|
||||||
The KES controller is instantiated with a specific controller name
|
- provider
|
||||||
and filters ES based on this property'
|
|
||||||
type: string
|
|
||||||
type: object
|
type: object
|
||||||
status:
|
status:
|
||||||
description: SecretStoreStatus defines the observed state of the SecretStore
|
description: SecretStoreStatus defines the observed state of the SecretStore
|
||||||
|
@ -117,9 +128,6 @@ spec:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
version: v1alpha1
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
served: true
|
||||||
storage: true
|
storage: true
|
||||||
status:
|
status:
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -6,6 +6,7 @@ require (
|
||||||
github.com/go-logr/logr v0.1.0
|
github.com/go-logr/logr v0.1.0
|
||||||
github.com/onsi/ginkgo v1.11.0
|
github.com/onsi/ginkgo v1.11.0
|
||||||
github.com/onsi/gomega v1.8.1
|
github.com/onsi/gomega v1.8.1
|
||||||
|
github.com/stretchr/testify v1.4.0
|
||||||
k8s.io/api v0.17.2
|
k8s.io/api v0.17.2
|
||||||
k8s.io/apimachinery v0.17.2
|
k8s.io/apimachinery v0.17.2
|
||||||
k8s.io/client-go v0.17.2
|
k8s.io/client-go v0.17.2
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -36,6 +36,7 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
|
||||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||||
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
|
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
||||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
|
@ -277,6 +278,7 @@ github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
|
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 h1:VcrIfasaLFkyjk6KNlXQSzO+B0fZcnECiDrKJsfxka0=
|
||||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||||
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||||
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||||
|
|
49
pkg/provider/aws/secretsmanager/secretsmanager.go
Normal file
49
pkg/provider/aws/secretsmanager/secretsmanager.go
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
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 secretsmanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
esv1alpha1 "github.com/external-secrets/external-secrets/api/v1alpha1"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/provider"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/provider/schema"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SecretsManager is a provider for AWS SecretsManager
|
||||||
|
type SecretsManager struct{}
|
||||||
|
|
||||||
|
// New constructs a SecretsManager Provider
|
||||||
|
func (sm *SecretsManager) New(ctx context.Context, store esv1alpha1.SecretStoreProvider, kube client.Client, namespace string) (provider.Provider, error) {
|
||||||
|
return sm, nil // stub
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSecret returns a single secret from the provider
|
||||||
|
func (sm *SecretsManager) GetSecret(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
|
||||||
|
return []byte("NOOP"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSecretMap returns multiple k/v pairs from the provider
|
||||||
|
func (sm *SecretsManager) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
|
||||||
|
return map[string][]byte{
|
||||||
|
"noop": []byte("NOOP"),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
schema.Register(&SecretsManager{}, &esv1alpha1.SecretStoreProvider{
|
||||||
|
AWSSM: &esv1alpha1.AWSSMProvider{},
|
||||||
|
})
|
||||||
|
}
|
1
pkg/provider/aws/secretsmanager/secretsmanager_test.go
Normal file
1
pkg/provider/aws/secretsmanager/secretsmanager_test.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package secretsmanager
|
100
pkg/provider/fake/fake.go
Normal file
100
pkg/provider/fake/fake.go
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
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 fake
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
esv1alpha1 "github.com/external-secrets/external-secrets/api/v1alpha1"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/provider"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/provider/schema"
|
||||||
|
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ provider.Provider = &Client{}
|
||||||
|
|
||||||
|
// Client is a fake client for testing
|
||||||
|
type Client struct {
|
||||||
|
NewFn func(context.Context, esv1alpha1.SecretStoreProvider, client.Client,
|
||||||
|
string) (provider.Provider, error)
|
||||||
|
GetSecretFn func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error)
|
||||||
|
GetSecretMapFn func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a fake client
|
||||||
|
func New() *Client {
|
||||||
|
v := &Client{
|
||||||
|
GetSecretFn: func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
GetSecretMapFn: func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
v.NewFn = func(context.Context, esv1alpha1.SecretStoreProvider, client.Client, string) (provider.Provider, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterAs registers the fake client in the schema
|
||||||
|
func (v *Client) RegisterAs(provider *esv1alpha1.SecretStoreProvider) {
|
||||||
|
schema.ForceRegister(v, provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSecret implements the provider.Provider interface
|
||||||
|
func (v *Client) GetSecret(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
|
||||||
|
return v.GetSecretFn(ctx, ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithGetSecret wraps secret data returned by this provider
|
||||||
|
func (v *Client) WithGetSecret(secData []byte, err error) *Client {
|
||||||
|
v.GetSecretFn = func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
|
||||||
|
return secData, err
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSecretMap imeplements the provider.Provider interface
|
||||||
|
func (v *Client) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
|
||||||
|
return v.GetSecretMapFn(ctx, ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithGetSecretMap wraps the secret data map returned by this fake provider
|
||||||
|
func (v *Client) WithGetSecretMap(secData map[string][]byte, err error) *Client {
|
||||||
|
v.GetSecretMapFn = func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
|
||||||
|
return secData, err
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithNew wraps the fake provider factory function
|
||||||
|
func (v *Client) WithNew(f func(context.Context, esv1alpha1.SecretStoreProvider, client.Client,
|
||||||
|
string) (provider.Provider, error)) *Client {
|
||||||
|
v.NewFn = f
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a new fake provider
|
||||||
|
func (v *Client) New(ctx context.Context, store esv1alpha1.SecretStoreProvider, kube client.Client, namespace string) (provider.Provider, error) {
|
||||||
|
client, err := v.NewFn(ctx, store, kube, namespace)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return client, nil
|
||||||
|
}
|
35
pkg/provider/provider.go
Normal file
35
pkg/provider/provider.go
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
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 provider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
esv1alpha1 "github.com/external-secrets/external-secrets/api/v1alpha1"
|
||||||
|
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Provider is a common interface for interacting with secret backends
|
||||||
|
type Provider interface {
|
||||||
|
// New constructs a SecretsManager Provider
|
||||||
|
New(ctx context.Context, store esv1alpha1.SecretStoreProvider, kube client.Client, namespace string) (Provider, error)
|
||||||
|
|
||||||
|
// GetSecret returns a single secret from the provider
|
||||||
|
GetSecret(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error)
|
||||||
|
|
||||||
|
// GetSecretMap returns multiple k/v pairs from the provider
|
||||||
|
GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error)
|
||||||
|
}
|
21
pkg/provider/register/register.go
Normal file
21
pkg/provider/register/register.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
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 register
|
||||||
|
|
||||||
|
// packages imported here are registered to the controller schema
|
||||||
|
import (
|
||||||
|
// register awssm provider
|
||||||
|
_ "github.com/external-secrets/external-secrets/pkg/provider/aws/secretsmanager"
|
||||||
|
)
|
114
pkg/provider/schema/schema.go
Normal file
114
pkg/provider/schema/schema.go
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
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 schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
esv1alpha1 "github.com/external-secrets/external-secrets/api/v1alpha1"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/provider"
|
||||||
|
)
|
||||||
|
|
||||||
|
var builder map[string]provider.Provider
|
||||||
|
var buildlock sync.RWMutex
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
builder = make(map[string]provider.Provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register a store backend type. Register panics if a
|
||||||
|
// backend with the same store is already registered
|
||||||
|
func Register(s provider.Provider, storeSpec *esv1alpha1.SecretStoreProvider) {
|
||||||
|
storeName, err := getProviderName(storeSpec)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("store error registering schema: %s", err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
buildlock.Lock()
|
||||||
|
defer buildlock.Unlock()
|
||||||
|
_, exists := builder[storeName]
|
||||||
|
if exists {
|
||||||
|
panic(fmt.Sprintf("store %q already registered", storeName))
|
||||||
|
}
|
||||||
|
|
||||||
|
builder[storeName] = s
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForceRegister adds to store schema, overwriting a store if
|
||||||
|
// already registered. Should only be used for testing
|
||||||
|
func ForceRegister(s provider.Provider, storeSpec *esv1alpha1.SecretStoreProvider) {
|
||||||
|
storeName, err := getProviderName(storeSpec)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("store error registering schema: %s", err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
buildlock.Lock()
|
||||||
|
builder[storeName] = s
|
||||||
|
buildlock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProviderByName returns the provider implementation by name
|
||||||
|
func GetProviderByName(name string) (provider.Provider, bool) {
|
||||||
|
buildlock.RLock()
|
||||||
|
f, ok := builder[name]
|
||||||
|
buildlock.RUnlock()
|
||||||
|
return f, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProvider returns the provider from the generic store
|
||||||
|
func GetProvider(s esv1alpha1.GenericStore) (provider.Provider, error) {
|
||||||
|
provider := s.GetProvider()
|
||||||
|
storeName, err := getProviderName(provider)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("store error for %s: %w", s.GetName(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buildlock.RLock()
|
||||||
|
f, ok := builder[storeName]
|
||||||
|
buildlock.RUnlock()
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("failed to find registered store backend for type: %s, name: %s", storeName, s.GetName())
|
||||||
|
}
|
||||||
|
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getProviderName returns the name of the configured provider
|
||||||
|
// or an error if the provider is not configured
|
||||||
|
func getProviderName(storeSpec *esv1alpha1.SecretStoreProvider) (string, error) {
|
||||||
|
storeBytes, err := json.Marshal(storeSpec)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to marshal store spec: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
storeMap := make(map[string]interface{})
|
||||||
|
err = json.Unmarshal(storeBytes, &storeMap)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to unmarshal store spec: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(storeMap) != 1 {
|
||||||
|
return "", fmt.Errorf("secret stores must only have exactly one backend specified, found %d", len(storeMap))
|
||||||
|
}
|
||||||
|
|
||||||
|
for k := range storeMap {
|
||||||
|
return k, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("failed to find registered store backend")
|
||||||
|
}
|
53
pkg/provider/schema/schema_test.go
Normal file
53
pkg/provider/schema/schema_test.go
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
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 schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
esv1alpha1 "github.com/external-secrets/external-secrets/api/v1alpha1"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/provider"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PP struct{}
|
||||||
|
|
||||||
|
// New constructs a SecretsManager Provider
|
||||||
|
func (p *PP) New(ctx context.Context, store esv1alpha1.SecretStoreProvider, kube client.Client, namespace string) (provider.Provider, error) {
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSecret returns a single secret from the provider
|
||||||
|
func (p *PP) GetSecret(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
|
||||||
|
return []byte("NOOP"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSecretMap returns multiple k/v pairs from the provider
|
||||||
|
func (p *PP) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
|
||||||
|
return map[string][]byte{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRegister(t *testing.T) {
|
||||||
|
p, ok := GetProviderByName("awssm")
|
||||||
|
assert.Nil(t, p)
|
||||||
|
assert.False(t, ok)
|
||||||
|
ForceRegister(&PP{}, &esv1alpha1.SecretStoreProvider{
|
||||||
|
AWSSM: &esv1alpha1.AWSSMProvider{},
|
||||||
|
})
|
||||||
|
p, ok = GetProviderByName("awssm")
|
||||||
|
assert.NotNil(t, p)
|
||||||
|
assert.True(t, ok)
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
package awssm
|
|
|
@ -1 +0,0 @@
|
||||||
package awssm
|
|
Loading…
Reference in a new issue