1
0
Fork 0
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:
Kellin McAvoy 2020-11-30 21:56:51 +01:00 committed by Moritz Johner
parent ffd4a220d1
commit f1fb6cfa06
17 changed files with 725 additions and 257 deletions

View 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()
}

View file

@ -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()
)

View file

@ -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"`

View file

@ -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)
} }
} }

View file

@ -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:

View file

@ -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
View file

@ -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
View file

@ -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=

View 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{},
})
}

View file

@ -0,0 +1 @@
package secretsmanager

100
pkg/provider/fake/fake.go Normal file
View 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
View 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)
}

View 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"
)

View 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")
}

View 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)
}

View file

@ -1 +0,0 @@
package awssm

View file

@ -1 +0,0 @@
package awssm