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
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"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 = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// SecretStore type metadata.
|
||||
var (
|
||||
SecretStoreKind = reflect.TypeOf(SecretStore{}).Name()
|
||||
SecretStoreKindAPIVersion = SecretStoreKind + "." + GroupVersion.String()
|
||||
)
|
||||
|
|
|
@ -34,6 +34,14 @@ type SecretStoreSpec struct {
|
|||
// +optional
|
||||
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
|
||||
// +optional
|
||||
AWSSM *AWSSMProvider `json:"awssm,omitempty"`
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
|
||||
|
||||
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
|
||||
|
@ -21,7 +19,7 @@ limitations under the License.
|
|||
package v1alpha1
|
||||
|
||||
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.
|
||||
|
@ -368,6 +366,26 @@ func (in *SecretStoreList) DeepCopyObject() runtime.Object {
|
|||
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.
|
||||
func (in *SecretStoreRef) DeepCopyInto(out *SecretStoreRef) {
|
||||
*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.
|
||||
func (in *SecretStoreSpec) DeepCopyInto(out *SecretStoreSpec) {
|
||||
*out = *in
|
||||
if in.AWSSM != nil {
|
||||
in, out := &in.AWSSM, &out.AWSSM
|
||||
*out = new(AWSSMProvider)
|
||||
if in.Provider != nil {
|
||||
in, out := &in.Provider, &out.Provider
|
||||
*out = new(SecretStoreProvider)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.2.5
|
||||
controller-gen.kubebuilder.io/version: v0.4.1
|
||||
creationTimestamp: null
|
||||
name: externalsecrets.external-secrets.io
|
||||
spec:
|
||||
|
@ -15,7 +15,9 @@ spec:
|
|||
plural: externalsecrets
|
||||
singular: externalsecret
|
||||
scope: Namespaced
|
||||
validation:
|
||||
versions:
|
||||
- name: v1alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: ExternalSecret is the Schema for the externalsecrets API
|
||||
properties:
|
||||
|
@ -68,8 +70,8 @@ spec:
|
|||
type: array
|
||||
dataFrom:
|
||||
description: DataFrom is used to fetch all properties from a specific
|
||||
Provider data If multiple entries are specified, the Secret keys are
|
||||
merged in the specified order
|
||||
Provider data If multiple entries are specified, the Secret keys
|
||||
are merged in the specified order
|
||||
items:
|
||||
description: ExternalSecretDataRemoteRef defines Provider data location
|
||||
properties:
|
||||
|
@ -90,17 +92,18 @@ spec:
|
|||
type: array
|
||||
refreshInterval:
|
||||
description: 'RefreshInterval is the amount of time before the values
|
||||
reading again from the SecretStore provider Valid time units are "ns",
|
||||
"us" (or "µs"), "ms", "s", "m", "h" (from time.ParseDuration) May
|
||||
be set to zero to fetch and create it once TODO: Default to some value?'
|
||||
reading again from the SecretStore provider Valid time units are
|
||||
"ns", "us" (or "µs"), "ms", "s", "m", "h" (from time.ParseDuration)
|
||||
May be set to zero to fetch and create it once TODO: Default to
|
||||
some value?'
|
||||
type: string
|
||||
secretStoreRef:
|
||||
description: SecretStoreRef defines which SecretStore to fetch the ExternalSecret
|
||||
data
|
||||
description: SecretStoreRef defines which SecretStore to fetch the
|
||||
ExternalSecret data
|
||||
properties:
|
||||
kind:
|
||||
description: Kind of the SecretStore resource (SecretStore or ClusterSecretStore)
|
||||
Defaults to `SecretStore`
|
||||
description: Kind of the SecretStore resource (SecretStore or
|
||||
ClusterSecretStore) Defaults to `SecretStore`
|
||||
type: string
|
||||
name:
|
||||
description: Name of the SecretStore resource
|
||||
|
@ -109,12 +112,12 @@ spec:
|
|||
- name
|
||||
type: object
|
||||
target:
|
||||
description: ExternalSecretTarget defines the Kubernetes Secret to be
|
||||
created There can be only one target per ExternalSecret
|
||||
description: ExternalSecretTarget defines the Kubernetes Secret to
|
||||
be created There can be only one target per ExternalSecret
|
||||
properties:
|
||||
creationPolicy:
|
||||
description: CreationPolicy defines rules on how to create the resulting
|
||||
Secret Defaults to 'Owner'
|
||||
description: CreationPolicy defines rules on how to create the
|
||||
resulting Secret Defaults to 'Owner'
|
||||
type: string
|
||||
name:
|
||||
description: Name defines the name of the Secret resource to be
|
||||
|
@ -156,9 +159,6 @@ spec:
|
|||
type: string
|
||||
type: object
|
||||
type: object
|
||||
version: v1alpha1
|
||||
versions:
|
||||
- name: v1alpha1
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.2.5
|
||||
controller-gen.kubebuilder.io/version: v0.4.1
|
||||
creationTimestamp: null
|
||||
name: secretstores.external-secrets.io
|
||||
spec:
|
||||
|
@ -15,7 +15,9 @@ spec:
|
|||
plural: secretstores
|
||||
singular: secretstore
|
||||
scope: Namespaced
|
||||
validation:
|
||||
versions:
|
||||
- name: v1alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: SecretStore is the Schema for the secretstores API
|
||||
properties:
|
||||
|
@ -33,10 +35,21 @@ spec:
|
|||
type: object
|
||||
spec:
|
||||
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:
|
||||
awssm:
|
||||
description: AWSSM configures this store to sync secrets using AWS Secret
|
||||
Manager provider
|
||||
description: AWSSM configures this store to sync secrets using
|
||||
AWS Secret Manager provider
|
||||
properties:
|
||||
auth:
|
||||
description: Auth defines the information necessary to authenticate
|
||||
|
@ -85,11 +98,9 @@ spec:
|
|||
- auth
|
||||
- region
|
||||
type: object
|
||||
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
|
||||
type: object
|
||||
required:
|
||||
- provider
|
||||
type: object
|
||||
status:
|
||||
description: SecretStoreStatus defines the observed state of the SecretStore
|
||||
|
@ -117,9 +128,6 @@ spec:
|
|||
type: string
|
||||
type: object
|
||||
type: object
|
||||
version: v1alpha1
|
||||
versions:
|
||||
- name: v1alpha1
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
|
|
1
go.mod
1
go.mod
|
@ -6,6 +6,7 @@ require (
|
|||
github.com/go-logr/logr v0.1.0
|
||||
github.com/onsi/ginkgo v1.11.0
|
||||
github.com/onsi/gomega v1.8.1
|
||||
github.com/stretchr/testify v1.4.0
|
||||
k8s.io/api v0.17.2
|
||||
k8s.io/apimachinery 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-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.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
||||
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-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/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/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.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=
|
||||
|
|
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