Browse Source

feat: awssm refactoring (#57)

* fix: refactor awssm provider
Moritz Johner 5 years ago
parent
commit
640978ca9e

+ 24 - 8
apis/externalsecrets/v1alpha1/secretstore_awssm_types.go

@@ -18,14 +18,14 @@ import (
 	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
 	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
 )
 )
 
 
-// AWSSMAuth contains a secretRef for credentials.
-type AWSSMAuth struct {
-	SecretRef AWSSMAuthSecretRef `json:"secretRef"`
+// AWSAuth contains a secretRef for credentials.
+type AWSAuth struct {
+	SecretRef AWSAuthSecretRef `json:"secretRef"`
 }
 }
 
 
-// AWSSMAuthSecretRef holds secret references for aws credentials
+// AWSAuthSecretRef holds secret references for aws credentials
 // both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate.
 // both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate.
-type AWSSMAuthSecretRef struct {
+type AWSAuthSecretRef struct {
 	// The AccessKeyID is used for authentication
 	// The AccessKeyID is used for authentication
 	AccessKeyID esmeta.SecretKeySelector `json:"accessKeyIDSecretRef,omitempty"`
 	AccessKeyID esmeta.SecretKeySelector `json:"accessKeyIDSecretRef,omitempty"`
 
 
@@ -33,14 +33,30 @@ type AWSSMAuthSecretRef struct {
 	SecretAccessKey esmeta.SecretKeySelector `json:"secretAccessKeySecretRef,omitempty"`
 	SecretAccessKey esmeta.SecretKeySelector `json:"secretAccessKeySecretRef,omitempty"`
 }
 }
 
 
-// AWSSMProvider configures a store to sync secrets using the AWS Secret Manager provider.
-type AWSSMProvider struct {
+// AWSServiceType is a enum that defines the service/API that is used to fetch the secrets.
+// +kubebuilder:validation:Enum=SecretsManager;ParameterStore
+type AWSServiceType string
+
+const (
+	// AWSServiceSecretsManager is the AWS SecretsManager.
+	// see: https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html
+	AWSServiceSecretsManager AWSServiceType = "SecretsManager"
+	// AWSServiceParameterStore is the AWS SystemsManager ParameterStore.
+	// see: https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html
+	AWSServiceParameterStore AWSServiceType = "ParameterStore"
+)
+
+// AWSProvider configures a store to sync secrets with AWS.
+type AWSProvider struct {
+	// Service defines which service should be used to fetch the secrets
+	Service AWSServiceType `json:"service"`
+
 	// Auth defines the information necessary to authenticate against AWS
 	// Auth defines the information necessary to authenticate against AWS
 	// if not set aws sdk will infer credentials from your environment
 	// if not set aws sdk will infer credentials from your environment
 	// see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials
 	// see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials
 	// +nullable
 	// +nullable
 	// +optional
 	// +optional
-	Auth *AWSSMAuth `json:"auth"`
+	Auth *AWSAuth `json:"auth"`
 
 
 	// Role is a Role ARN which the SecretManager provider will assume
 	// Role is a Role ARN which the SecretManager provider will assume
 	// +optional
 	// +optional

+ 2 - 10
apis/externalsecrets/v1alpha1/secretstore_types.go

@@ -19,14 +19,6 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 )
 
 
-type StoreProvider string
-
-const (
-	AWSSM StoreProvider = "AWSSM"
-	GCPSM StoreProvider = "GCPSM"
-	Vault StoreProvider = "VAULT"
-)
-
 // SecretStoreSpec defines the desired state of SecretStore.
 // SecretStoreSpec defines the desired state of SecretStore.
 type SecretStoreSpec struct {
 type SecretStoreSpec struct {
 	// Used to select the correct KES controller (think: ingress.ingressClassName)
 	// Used to select the correct KES controller (think: ingress.ingressClassName)
@@ -42,9 +34,9 @@ type SecretStoreSpec struct {
 // +kubebuilder:validation:MinProperties=1
 // +kubebuilder:validation:MinProperties=1
 // +kubebuilder:validation:MaxProperties=1
 // +kubebuilder:validation:MaxProperties=1
 type SecretStoreProvider struct {
 type SecretStoreProvider struct {
-	// AWSSM configures this store to sync secrets using AWS Secret Manager provider
+	// AWS configures this store to sync secrets using AWS Secret Manager provider
 	// +optional
 	// +optional
-	AWSSM *AWSSMProvider `json:"awssm,omitempty"`
+	AWS *AWSProvider `json:"aws,omitempty"`
 }
 }
 
 
 type SecretStoreConditionType string
 type SecretStoreConditionType string

+ 16 - 16
apis/externalsecrets/v1alpha1/zz_generated.deepcopy.go

@@ -24,54 +24,54 @@ import (
 )
 )
 
 
 // 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 *AWSSMAuth) DeepCopyInto(out *AWSSMAuth) {
+func (in *AWSAuth) DeepCopyInto(out *AWSAuth) {
 	*out = *in
 	*out = *in
 	in.SecretRef.DeepCopyInto(&out.SecretRef)
 	in.SecretRef.DeepCopyInto(&out.SecretRef)
 }
 }
 
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSSMAuth.
-func (in *AWSSMAuth) DeepCopy() *AWSSMAuth {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSAuth.
+func (in *AWSAuth) DeepCopy() *AWSAuth {
 	if in == nil {
 	if in == nil {
 		return nil
 		return nil
 	}
 	}
-	out := new(AWSSMAuth)
+	out := new(AWSAuth)
 	in.DeepCopyInto(out)
 	in.DeepCopyInto(out)
 	return 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 *AWSSMAuthSecretRef) DeepCopyInto(out *AWSSMAuthSecretRef) {
+func (in *AWSAuthSecretRef) DeepCopyInto(out *AWSAuthSecretRef) {
 	*out = *in
 	*out = *in
 	in.AccessKeyID.DeepCopyInto(&out.AccessKeyID)
 	in.AccessKeyID.DeepCopyInto(&out.AccessKeyID)
 	in.SecretAccessKey.DeepCopyInto(&out.SecretAccessKey)
 	in.SecretAccessKey.DeepCopyInto(&out.SecretAccessKey)
 }
 }
 
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSSMAuthSecretRef.
-func (in *AWSSMAuthSecretRef) DeepCopy() *AWSSMAuthSecretRef {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSAuthSecretRef.
+func (in *AWSAuthSecretRef) DeepCopy() *AWSAuthSecretRef {
 	if in == nil {
 	if in == nil {
 		return nil
 		return nil
 	}
 	}
-	out := new(AWSSMAuthSecretRef)
+	out := new(AWSAuthSecretRef)
 	in.DeepCopyInto(out)
 	in.DeepCopyInto(out)
 	return 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 *AWSSMProvider) DeepCopyInto(out *AWSSMProvider) {
+func (in *AWSProvider) DeepCopyInto(out *AWSProvider) {
 	*out = *in
 	*out = *in
 	if in.Auth != nil {
 	if in.Auth != nil {
 		in, out := &in.Auth, &out.Auth
 		in, out := &in.Auth, &out.Auth
-		*out = new(AWSSMAuth)
+		*out = new(AWSAuth)
 		(*in).DeepCopyInto(*out)
 		(*in).DeepCopyInto(*out)
 	}
 	}
 }
 }
 
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSSMProvider.
-func (in *AWSSMProvider) DeepCopy() *AWSSMProvider {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSProvider.
+func (in *AWSProvider) DeepCopy() *AWSProvider {
 	if in == nil {
 	if in == nil {
 		return nil
 		return nil
 	}
 	}
-	out := new(AWSSMProvider)
+	out := new(AWSProvider)
 	in.DeepCopyInto(out)
 	in.DeepCopyInto(out)
 	return out
 	return out
 }
 }
@@ -417,9 +417,9 @@ func (in *SecretStoreList) DeepCopyObject() runtime.Object {
 // 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 *SecretStoreProvider) DeepCopyInto(out *SecretStoreProvider) {
 func (in *SecretStoreProvider) DeepCopyInto(out *SecretStoreProvider) {
 	*out = *in
 	*out = *in
-	if in.AWSSM != nil {
-		in, out := &in.AWSSM, &out.AWSSM
-		*out = new(AWSSMProvider)
+	if in.AWS != nil {
+		in, out := &in.AWS, &out.AWS
+		*out = new(AWSProvider)
 		(*in).DeepCopyInto(*out)
 		(*in).DeepCopyInto(*out)
 	}
 	}
 }
 }

+ 12 - 4
config/crd/bases/external-secrets.io_clustersecretstores.yaml

@@ -54,9 +54,9 @@ spec:
                 maxProperties: 1
                 maxProperties: 1
                 minProperties: 1
                 minProperties: 1
                 properties:
                 properties:
-                  awssm:
-                    description: AWSSM configures this store to sync secrets using
-                      AWS Secret Manager provider
+                  aws:
+                    description: AWS configures this store to sync secrets using AWS
+                      Secret Manager provider
                     properties:
                     properties:
                       auth:
                       auth:
                         description: 'Auth defines the information necessary to authenticate
                         description: 'Auth defines the information necessary to authenticate
@@ -65,7 +65,7 @@ spec:
                         nullable: true
                         nullable: true
                         properties:
                         properties:
                           secretRef:
                           secretRef:
-                            description: AWSSMAuthSecretRef holds secret references
+                            description: AWSAuthSecretRef holds secret references
                               for aws credentials both AccessKeyID and SecretAccessKey
                               for aws credentials both AccessKeyID and SecretAccessKey
                               must be defined in order to properly authenticate.
                               must be defined in order to properly authenticate.
                             properties:
                             properties:
@@ -124,8 +124,16 @@ spec:
                         description: Role is a Role ARN which the SecretManager provider
                         description: Role is a Role ARN which the SecretManager provider
                           will assume
                           will assume
                         type: string
                         type: string
+                      service:
+                        description: Service defines which service should be used
+                          to fetch the secrets
+                        enum:
+                        - SecretsManager
+                        - ParameterStore
+                        type: string
                     required:
                     required:
                     - region
                     - region
+                    - service
                     type: object
                     type: object
                 type: object
                 type: object
             required:
             required:

+ 12 - 4
config/crd/bases/external-secrets.io_secretstores.yaml

@@ -54,9 +54,9 @@ spec:
                 maxProperties: 1
                 maxProperties: 1
                 minProperties: 1
                 minProperties: 1
                 properties:
                 properties:
-                  awssm:
-                    description: AWSSM configures this store to sync secrets using
-                      AWS Secret Manager provider
+                  aws:
+                    description: AWS configures this store to sync secrets using AWS
+                      Secret Manager provider
                     properties:
                     properties:
                       auth:
                       auth:
                         description: 'Auth defines the information necessary to authenticate
                         description: 'Auth defines the information necessary to authenticate
@@ -65,7 +65,7 @@ spec:
                         nullable: true
                         nullable: true
                         properties:
                         properties:
                           secretRef:
                           secretRef:
-                            description: AWSSMAuthSecretRef holds secret references
+                            description: AWSAuthSecretRef holds secret references
                               for aws credentials both AccessKeyID and SecretAccessKey
                               for aws credentials both AccessKeyID and SecretAccessKey
                               must be defined in order to properly authenticate.
                               must be defined in order to properly authenticate.
                             properties:
                             properties:
@@ -124,8 +124,16 @@ spec:
                         description: Role is a Role ARN which the SecretManager provider
                         description: Role is a Role ARN which the SecretManager provider
                           will assume
                           will assume
                         type: string
                         type: string
+                      service:
+                        description: Service defines which service should be used
+                          to fetch the secrets
+                        enum:
+                        - SecretsManager
+                        - ParameterStore
+                        type: string
                     required:
                     required:
                     - region
                     - region
+                    - service
                     type: object
                     type: object
                 type: object
                 type: object
             required:
             required:

+ 4 - 4
config/samples/external-secrets_v1alpha1_secretstore.yaml

@@ -6,7 +6,10 @@ spec:
   controller: dev
   controller: dev
 
 
   provider:
   provider:
-    awssm:
+    aws:
+      service: SecretsManager
+      role: iam-role
+      region: eu-central-1
       auth:
       auth:
         secretRef:
         secretRef:
           accessKeyIDSecretRef:
           accessKeyIDSecretRef:
@@ -16,6 +19,3 @@ spec:
           secretAccessKeySecretRef:
           secretAccessKeySecretRef:
             name: awssm-secret
             name: awssm-secret
             key: secret-access-key
             key: secret-access-key
-
-      role: iam-role
-      region: eu-central-1

+ 1 - 1
docs/provider-aws-secrets-manager.md

@@ -9,7 +9,7 @@
 
 
 A `SecretStore` points to AWS Secrets Manager in a certain account within a
 A `SecretStore` points to AWS Secrets Manager in a certain account within a
 defined region. You should define Roles that allow fine-grained access to
 defined region. You should define Roles that allow fine-grained access to
-individual secrets and pass them to ESO using `spec.provider.awssm.role`. This
+individual secrets and pass them to ESO using `spec.provider.aws.role`. This
 way users of the `SecretStore` can only access the secrets necessary.
 way users of the `SecretStore` can only access the secrets necessary.
 
 
 ``` yaml
 ``` yaml

+ 2 - 1
docs/snippets/aws-sm-store.yaml

@@ -5,7 +5,8 @@ metadata:
 spec:
 spec:
   controller: dev
   controller: dev
   provider:
   provider:
-    awssm:
+    aws:
+      service: SecretsManager
       # define a specific role to limit access
       # define a specific role to limit access
       # to certain secrets
       # to certain secrets
       role: iam-role
       role: iam-role

+ 2 - 1
docs/snippets/basic-secret-store.yaml

@@ -5,7 +5,8 @@ metadata:
 spec:
 spec:
   controller: dev
   controller: dev
   provider:
   provider:
-    awssm:
+    aws:
+      service: SecretsManager
       role: arn:aws:iam::123456789012:role/team-a-reader
       role: arn:aws:iam::123456789012:role/team-a-reader
       region: us-east-1
       region: us-east-1
       auth:
       auth:

+ 4 - 3
docs/snippets/full-secret-store.yaml

@@ -1,7 +1,7 @@
 apiVerson: external-secrets.io/v1alpha1
 apiVerson: external-secrets.io/v1alpha1
 kind: SecretStore
 kind: SecretStore
 metadata:
 metadata:
-  name: vault
+  name: example
   namespace: example-ns
   namespace: example-ns
 spec:
 spec:
 
 
@@ -15,8 +15,9 @@ spec:
   provider:
   provider:
 
 
     # (1): AWS Secrets Manager
     # (1): AWS Secrets Manager
-    # AWSSM configures this store to sync secrets using AWS Secret Manager provider
-    awssm:
+    # aws configures this store to sync secrets using AWS Secret Manager provider
+    aws:
+      service: SecretsManager
       # Role is a Role ARN which the SecretManager provider will assume
       # Role is a Role ARN which the SecretManager provider will assume
       role: iam-role
       role: iam-role
       # AWS Region to be used for the provider
       # AWS Region to be used for the provider

+ 73 - 47
docs/spec.md

@@ -10,14 +10,14 @@
 </p>
 </p>
 Resource Types:
 Resource Types:
 <ul></ul>
 <ul></ul>
-<h3 id="external-secrets.io/v1alpha1.AWSSMAuth">AWSSMAuth
+<h3 id="external-secrets.io/v1alpha1.AWSAuth">AWSAuth
 </h3>
 </h3>
 <p>
 <p>
 (<em>Appears on:</em>
 (<em>Appears on:</em>
-<a href="#external-secrets.io/v1alpha1.AWSSMProvider">AWSSMProvider</a>)
+<a href="#external-secrets.io/v1alpha1.AWSProvider">AWSProvider</a>)
 </p>
 </p>
 <p>
 <p>
-<p>AWSSMAuth contains a secretRef for credentials.</p>
+<p>AWSAuth contains a secretRef for credentials.</p>
 </p>
 </p>
 <table>
 <table>
 <thead>
 <thead>
@@ -31,8 +31,8 @@ Resource Types:
 <td>
 <td>
 <code>secretRef</code></br>
 <code>secretRef</code></br>
 <em>
 <em>
-<a href="#external-secrets.io/v1alpha1.AWSSMAuthSecretRef">
-AWSSMAuthSecretRef
+<a href="#external-secrets.io/v1alpha1.AWSAuthSecretRef">
+AWSAuthSecretRef
 </a>
 </a>
 </em>
 </em>
 </td>
 </td>
@@ -41,14 +41,14 @@ AWSSMAuthSecretRef
 </tr>
 </tr>
 </tbody>
 </tbody>
 </table>
 </table>
-<h3 id="external-secrets.io/v1alpha1.AWSSMAuthSecretRef">AWSSMAuthSecretRef
+<h3 id="external-secrets.io/v1alpha1.AWSAuthSecretRef">AWSAuthSecretRef
 </h3>
 </h3>
 <p>
 <p>
 (<em>Appears on:</em>
 (<em>Appears on:</em>
-<a href="#external-secrets.io/v1alpha1.AWSSMAuth">AWSSMAuth</a>)
+<a href="#external-secrets.io/v1alpha1.AWSAuth">AWSAuth</a>)
 </p>
 </p>
 <p>
 <p>
-<p>AWSSMAuthSecretRef holds secret references for aws credentials
+<p>AWSAuthSecretRef holds secret references for aws credentials
 both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate.</p>
 both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate.</p>
 </p>
 </p>
 <table>
 <table>
@@ -83,14 +83,14 @@ github.com/external-secrets/external-secrets/apis/meta/v1.SecretKeySelector
 </tr>
 </tr>
 </tbody>
 </tbody>
 </table>
 </table>
-<h3 id="external-secrets.io/v1alpha1.AWSSMProvider">AWSSMProvider
+<h3 id="external-secrets.io/v1alpha1.AWSProvider">AWSProvider
 </h3>
 </h3>
 <p>
 <p>
 (<em>Appears on:</em>
 (<em>Appears on:</em>
 <a href="#external-secrets.io/v1alpha1.SecretStoreProvider">SecretStoreProvider</a>)
 <a href="#external-secrets.io/v1alpha1.SecretStoreProvider">SecretStoreProvider</a>)
 </p>
 </p>
 <p>
 <p>
-<p>AWSSMProvider configures a store to sync secrets using the AWS Secret Manager provider.</p>
+<p>AWSProvider configures a store to sync secrets using the AWS Secret Manager provider.</p>
 </p>
 </p>
 <table>
 <table>
 <thead>
 <thead>
@@ -102,10 +102,23 @@ github.com/external-secrets/external-secrets/apis/meta/v1.SecretKeySelector
 <tbody>
 <tbody>
 <tr>
 <tr>
 <td>
 <td>
+<code>service</code></br>
+<em>
+<a href="#external-secrets.io/v1alpha1.AWSServiceType">
+AWSServiceType
+</a>
+</em>
+</td>
+<td>
+<p>Service defines which service should be used to fetch the secrets</p>
+</td>
+</tr>
+<tr>
+<td>
 <code>auth</code></br>
 <code>auth</code></br>
 <em>
 <em>
-<a href="#external-secrets.io/v1alpha1.AWSSMAuth">
-AWSSMAuth
+<a href="#external-secrets.io/v1alpha1.AWSAuth">
+AWSAuth
 </a>
 </a>
 </em>
 </em>
 </td>
 </td>
@@ -141,6 +154,32 @@ string
 </tr>
 </tr>
 </tbody>
 </tbody>
 </table>
 </table>
+<h3 id="external-secrets.io/v1alpha1.AWSServiceType">AWSServiceType
+(<code>string</code> alias)</p></h3>
+<p>
+(<em>Appears on:</em>
+<a href="#external-secrets.io/v1alpha1.AWSProvider">AWSProvider</a>)
+</p>
+<p>
+<p>AWSServiceType is a enum that defines the service/API that is used to fetch the secrets</p>
+</p>
+<table>
+<thead>
+<tr>
+<th>Value</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody><tr><td><p>&#34;ParameterStore&#34;</p></td>
+<td><p>AWSServiceParameterStore is the AWS SystemsManager ParameterStore
+see: <a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html">https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html</a></p>
+</td>
+</tr><tr><td><p>&#34;SecretsManager&#34;</p></td>
+<td><p>AWSServiceSecretsManager is the AWS SecretsManager
+see: <a href="https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html">https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html</a></p>
+</td>
+</tr></tbody>
+</table>
 <h3 id="external-secrets.io/v1alpha1.ClusterSecretStore">ClusterSecretStore
 <h3 id="external-secrets.io/v1alpha1.ClusterSecretStore">ClusterSecretStore
 </h3>
 </h3>
 <p>
 <p>
@@ -280,15 +319,15 @@ ExternalSecretTarget
 <td>
 <td>
 <code>refreshInterval</code></br>
 <code>refreshInterval</code></br>
 <em>
 <em>
-string
+<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#duration-v1-meta">
+Kubernetes meta/v1.Duration
+</a>
 </em>
 </em>
 </td>
 </td>
 <td>
 <td>
-<em>(Optional)</em>
-<p>RefreshInterval is the amount of time before the values reading again from the SecretStore provider
-Valid time units are &ldquo;ns&rdquo;, &ldquo;us&rdquo; (or &ldquo;µs&rdquo;), &ldquo;ms&rdquo;, &ldquo;s&rdquo;, &ldquo;m&rdquo;, &ldquo;h&rdquo; (from time.ParseDuration)
-May be set to zero to fetch and create it once
-TODO: Default to some value?</p>
+<p>RefreshInterval is the amount of time before the values are read again from the SecretStore provider
+Valid time units are &ldquo;ns&rdquo;, &ldquo;us&rdquo; (or &ldquo;µs&rdquo;), &ldquo;ms&rdquo;, &ldquo;s&rdquo;, &ldquo;m&rdquo;, &ldquo;h&rdquo;
+May be set to zero to fetch and create it once. Defaults to 1h.</p>
 </td>
 </td>
 </tr>
 </tr>
 <tr>
 <tr>
@@ -524,15 +563,15 @@ ExternalSecretTarget
 <td>
 <td>
 <code>refreshInterval</code></br>
 <code>refreshInterval</code></br>
 <em>
 <em>
-string
+<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#duration-v1-meta">
+Kubernetes meta/v1.Duration
+</a>
 </em>
 </em>
 </td>
 </td>
 <td>
 <td>
-<em>(Optional)</em>
-<p>RefreshInterval is the amount of time before the values reading again from the SecretStore provider
-Valid time units are &ldquo;ns&rdquo;, &ldquo;us&rdquo; (or &ldquo;µs&rdquo;), &ldquo;ms&rdquo;, &ldquo;s&rdquo;, &ldquo;m&rdquo;, &ldquo;h&rdquo; (from time.ParseDuration)
-May be set to zero to fetch and create it once
-TODO: Default to some value?</p>
+<p>RefreshInterval is the amount of time before the values are read again from the SecretStore provider
+Valid time units are &ldquo;ns&rdquo;, &ldquo;us&rdquo; (or &ldquo;µs&rdquo;), &ldquo;ms&rdquo;, &ldquo;s&rdquo;, &ldquo;m&rdquo;, &ldquo;h&rdquo;
+May be set to zero to fetch and create it once. Defaults to 1h.</p>
 </td>
 </td>
 </tr>
 </tr>
 <tr>
 <tr>
@@ -825,6 +864,12 @@ map[string]string
 <p>GenericStore is a common interface for interacting with ClusterSecretStore
 <p>GenericStore is a common interface for interacting with ClusterSecretStore
 or a namespaced SecretStore.</p>
 or a namespaced SecretStore.</p>
 </p>
 </p>
+<h3 id="external-secrets.io/v1alpha1.ProviderIdentity">ProviderIdentity
+</h3>
+<p>
+<p>ProviderIdentity returns the name of a secret store provider
+this interface must be implemented by every provider</p>
+</p>
 <h3 id="external-secrets.io/v1alpha1.SecretStore">SecretStore
 <h3 id="external-secrets.io/v1alpha1.SecretStore">SecretStore
 </h3>
 </h3>
 <p>
 <p>
@@ -946,16 +991,16 @@ SecretStoreStatus
 <tbody>
 <tbody>
 <tr>
 <tr>
 <td>
 <td>
-<code>awssm</code></br>
+<code>aws</code></br>
 <em>
 <em>
-<a href="#external-secrets.io/v1alpha1.AWSSMProvider">
-AWSSMProvider
+<a href="#external-secrets.io/v1alpha1.AWSProvider">
+AWSProvider
 </a>
 </a>
 </em>
 </em>
 </td>
 </td>
 <td>
 <td>
 <em>(Optional)</em>
 <em>(Optional)</em>
-<p>AWSSM configures this store to sync secrets using AWS Secret Manager provider</p>
+<p>AWS configures this store to sync secrets using AWS Secret Manager provider</p>
 </td>
 </td>
 </tr>
 </tr>
 </tbody>
 </tbody>
@@ -1158,25 +1203,6 @@ Kubernetes meta/v1.Time
 </tr>
 </tr>
 </tbody>
 </tbody>
 </table>
 </table>
-<h3 id="external-secrets.io/v1alpha1.StoreProvider">StoreProvider
-(<code>string</code> alias)</p></h3>
-<p>
-</p>
-<table>
-<thead>
-<tr>
-<th>Value</th>
-<th>Description</th>
-</tr>
-</thead>
-<tbody><tr><td><p>&#34;AWSSM&#34;</p></td>
-<td></td>
-</tr><tr><td><p>&#34;GCPSM&#34;</p></td>
-<td></td>
-</tr><tr><td><p>&#34;VAULT&#34;</p></td>
-<td></td>
-</tr></tbody>
-</table>
 <hr/>
 <hr/>
 <p><em>
 <p><em>
 Generated with <code>gen-crd-api-reference-docs</code>.
 Generated with <code>gen-crd-api-reference-docs</code>.

+ 9 - 3
pkg/controllers/externalsecret/externalsecret_controller_test.go

@@ -56,7 +56,9 @@ var _ = Describe("ExternalSecret controller", func() {
 			},
 			},
 			Spec: esv1alpha1.SecretStoreSpec{
 			Spec: esv1alpha1.SecretStoreSpec{
 				Provider: &esv1alpha1.SecretStoreProvider{
 				Provider: &esv1alpha1.SecretStoreProvider{
-					AWSSM: &esv1alpha1.AWSSMProvider{},
+					AWS: &esv1alpha1.AWSProvider{
+						Service: esv1alpha1.AWSServiceSecretsManager,
+					},
 				},
 				},
 			},
 			},
 		})).To(Succeed())
 		})).To(Succeed())
@@ -427,7 +429,9 @@ var _ = Describe("ExternalSecret controller", func() {
 				Spec: esv1alpha1.SecretStoreSpec{
 				Spec: esv1alpha1.SecretStoreSpec{
 					Controller: "some-other-controller",
 					Controller: "some-other-controller",
 					Provider: &esv1alpha1.SecretStoreProvider{
 					Provider: &esv1alpha1.SecretStoreProvider{
-						AWSSM: &esv1alpha1.AWSSMProvider{},
+						AWS: &esv1alpha1.AWSProvider{
+							Service: esv1alpha1.AWSServiceSecretsManager,
+						},
 					},
 					},
 				},
 				},
 			})).To(Succeed())
 			})).To(Succeed())
@@ -509,6 +513,8 @@ func CreateNamespace(baseName string, c client.Client) (string, error) {
 func init() {
 func init() {
 	fakeProvider = fake.New()
 	fakeProvider = fake.New()
 	schema.ForceRegister(fakeProvider, &esv1alpha1.SecretStoreProvider{
 	schema.ForceRegister(fakeProvider, &esv1alpha1.SecretStoreProvider{
-		AWSSM: &esv1alpha1.AWSSMProvider{},
+		AWS: &esv1alpha1.AWSProvider{
+			Service: esv1alpha1.AWSServiceSecretsManager,
+		},
 	})
 	})
 }
 }

+ 60 - 0
pkg/provider/aws/parameterstore/parameterstore.go

@@ -0,0 +1,60 @@
+/*
+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 parameterstore
+
+import (
+	"context"
+
+	"github.com/aws/aws-sdk-go/service/ssm"
+	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+
+	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
+	"github.com/external-secrets/external-secrets/pkg/provider"
+	awssess "github.com/external-secrets/external-secrets/pkg/provider/aws/session"
+)
+
+// ParameterStore is a provider for AWS ParameterStore.
+type ParameterStore struct {
+	stsProvider awssess.STSProvider
+	// session     *session.Session
+	// client      PMInterface
+}
+
+// PMInterface is a subset of the parameterstore api.
+// see: https://docs.aws.amazon.com/sdk-for-go/api/service/ssm/ssmiface/
+type PMInterface interface {
+	GetParameter(*ssm.GetParameterInput) (*ssm.GetParameterOutput, error)
+}
+
+var log = ctrl.Log.WithName("provider").WithName("aws").WithName("parameterstore")
+
+// New constructs a ParameterStore Provider that is specific to a store.
+func New(ctx context.Context, store esv1alpha1.GenericStore, kube client.Client, namespace string, stsProvider awssess.STSProvider) (provider.SecretsClient, error) {
+	pm := &ParameterStore{
+		stsProvider: stsProvider,
+	}
+	return pm, nil
+}
+
+// GetSecret returns a single secret from the provider.
+func (pm *ParameterStore) GetSecret(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
+	log.Info("fetching secret value", "key", ref.Key)
+	return []byte("NOOP"), nil
+}
+
+// GetSecretMap returns multiple k/v pairs from the provider.
+func (pm *ParameterStore) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
+	return map[string][]byte{"NOOP": []byte("NOOP")}, nil
+}

+ 10 - 3
pkg/provider/aws/provider.go

@@ -8,6 +8,7 @@ import (
 
 
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
 	"github.com/external-secrets/external-secrets/pkg/provider"
 	"github.com/external-secrets/external-secrets/pkg/provider"
+	"github.com/external-secrets/external-secrets/pkg/provider/aws/parameterstore"
 	"github.com/external-secrets/external-secrets/pkg/provider/aws/secretsmanager"
 	"github.com/external-secrets/external-secrets/pkg/provider/aws/secretsmanager"
 	awssess "github.com/external-secrets/external-secrets/pkg/provider/aws/session"
 	awssess "github.com/external-secrets/external-secrets/pkg/provider/aws/session"
 	"github.com/external-secrets/external-secrets/pkg/provider/schema"
 	"github.com/external-secrets/external-secrets/pkg/provider/schema"
@@ -28,14 +29,20 @@ func (p *Provider) NewClient(ctx context.Context, store esv1alpha1.GenericStore,
 	if spec.Provider == nil {
 	if spec.Provider == nil {
 		return nil, fmt.Errorf("storeSpec is missing provider")
 		return nil, fmt.Errorf("storeSpec is missing provider")
 	}
 	}
-	if spec.Provider.AWSSM != nil {
+	if spec.Provider.AWS == nil {
+		return nil, fmt.Errorf("storeSpec is missing aws spec")
+	}
+	switch spec.Provider.AWS.Service {
+	case esv1alpha1.AWSServiceSecretsManager:
 		return secretsmanager.New(ctx, store, kube, namespace, awssess.DefaultSTSProvider)
 		return secretsmanager.New(ctx, store, kube, namespace, awssess.DefaultSTSProvider)
+	case esv1alpha1.AWSServiceParameterStore:
+		return parameterstore.New(ctx, store, kube, namespace, awssess.DefaultSTSProvider)
 	}
 	}
-	return nil, fmt.Errorf("AWS Provider spec missing")
+	return nil, fmt.Errorf("unknown AWS Provider Service: %s", spec.Provider.AWS.Service)
 }
 }
 
 
 func init() {
 func init() {
 	schema.Register(&Provider{}, &esv1alpha1.SecretStoreProvider{
 	schema.Register(&Provider{}, &esv1alpha1.SecretStoreProvider{
-		AWSSM: &esv1alpha1.AWSSMProvider{},
+		AWS: &esv1alpha1.AWSProvider{},
 	})
 	})
 }
 }

+ 3 - 1
pkg/provider/aws/provider_test.go

@@ -47,7 +47,9 @@ func TestProvider(t *testing.T) {
 			store: &esv1alpha1.SecretStore{
 			store: &esv1alpha1.SecretStore{
 				Spec: esv1alpha1.SecretStoreSpec{
 				Spec: esv1alpha1.SecretStoreSpec{
 					Provider: &esv1alpha1.SecretStoreProvider{
 					Provider: &esv1alpha1.SecretStoreProvider{
-						AWSSM: &esv1alpha1.AWSSMProvider{},
+						AWS: &esv1alpha1.AWSProvider{
+							Service: esv1alpha1.AWSServiceParameterStore,
+						},
 					},
 					},
 				},
 				},
 			},
 			},

+ 1 - 1
pkg/provider/aws/secretsmanager/secretsmanager.go

@@ -60,7 +60,7 @@ func New(ctx context.Context, store esv1alpha1.GenericStore, kube client.Client,
 	if spc.Provider == nil {
 	if spc.Provider == nil {
 		return nil, fmt.Errorf("storeSpec is missing provider")
 		return nil, fmt.Errorf("storeSpec is missing provider")
 	}
 	}
-	smProvider := spc.Provider.AWSSM
+	smProvider := spc.Provider.AWS
 	if smProvider == nil {
 	if smProvider == nil {
 		return nil, fmt.Errorf("invalid provider spec. Missing AWSSM field in store %s", store.GetObjectMeta().String())
 		return nil, fmt.Errorf("invalid provider spec. Missing AWSSM field in store %s", store.GetObjectMeta().String())
 	}
 	}

+ 22 - 22
pkg/provider/aws/secretsmanager/secretsmanager_test.go

@@ -71,7 +71,7 @@ func TestConstructor(t *testing.T) {
 			store: &esv1alpha1.SecretStore{
 			store: &esv1alpha1.SecretStore{
 				Spec: esv1alpha1.SecretStoreSpec{
 				Spec: esv1alpha1.SecretStoreSpec{
 					Provider: &esv1alpha1.SecretStoreProvider{
 					Provider: &esv1alpha1.SecretStoreProvider{
-						AWSSM: &esv1alpha1.AWSSMProvider{},
+						AWS: &esv1alpha1.AWSProvider{},
 					},
 					},
 				},
 				},
 			},
 			},
@@ -107,7 +107,7 @@ func TestConstructor(t *testing.T) {
 			store: &esv1alpha1.SecretStore{
 			store: &esv1alpha1.SecretStore{
 				Spec: esv1alpha1.SecretStoreSpec{
 				Spec: esv1alpha1.SecretStoreSpec{
 					Provider: &esv1alpha1.SecretStoreProvider{
 					Provider: &esv1alpha1.SecretStoreProvider{
-						AWSSM: &esv1alpha1.AWSSMProvider{
+						AWS: &esv1alpha1.AWSProvider{
 							Role: "foo-bar-baz",
 							Role: "foo-bar-baz",
 						},
 						},
 					},
 					},
@@ -127,9 +127,9 @@ func TestConstructor(t *testing.T) {
 			store: &esv1alpha1.SecretStore{
 			store: &esv1alpha1.SecretStore{
 				Spec: esv1alpha1.SecretStoreSpec{
 				Spec: esv1alpha1.SecretStoreSpec{
 					Provider: &esv1alpha1.SecretStoreProvider{
 					Provider: &esv1alpha1.SecretStoreProvider{
-						AWSSM: &esv1alpha1.AWSSMProvider{
-							Auth: &esv1alpha1.AWSSMAuth{
-								SecretRef: esv1alpha1.AWSSMAuthSecretRef{
+						AWS: &esv1alpha1.AWSProvider{
+							Auth: &esv1alpha1.AWSAuth{
+								SecretRef: esv1alpha1.AWSAuthSecretRef{
 									AccessKeyID: esmeta.SecretKeySelector{
 									AccessKeyID: esmeta.SecretKeySelector{
 										Name: "othersecret",
 										Name: "othersecret",
 										Key:  "one",
 										Key:  "one",
@@ -152,9 +152,9 @@ func TestConstructor(t *testing.T) {
 			store: &esv1alpha1.SecretStore{
 			store: &esv1alpha1.SecretStore{
 				Spec: esv1alpha1.SecretStoreSpec{
 				Spec: esv1alpha1.SecretStoreSpec{
 					Provider: &esv1alpha1.SecretStoreProvider{
 					Provider: &esv1alpha1.SecretStoreProvider{
-						AWSSM: &esv1alpha1.AWSSMProvider{
-							Auth: &esv1alpha1.AWSSMAuth{
-								SecretRef: esv1alpha1.AWSSMAuthSecretRef{
+						AWS: &esv1alpha1.AWSProvider{
+							Auth: &esv1alpha1.AWSAuth{
+								SecretRef: esv1alpha1.AWSAuthSecretRef{
 									AccessKeyID: esmeta.SecretKeySelector{
 									AccessKeyID: esmeta.SecretKeySelector{
 										Name: "onesecret",
 										Name: "onesecret",
 										// Namespace is not set
 										// Namespace is not set
@@ -193,9 +193,9 @@ func TestConstructor(t *testing.T) {
 			store: &esv1alpha1.SecretStore{
 			store: &esv1alpha1.SecretStore{
 				Spec: esv1alpha1.SecretStoreSpec{
 				Spec: esv1alpha1.SecretStoreSpec{
 					Provider: &esv1alpha1.SecretStoreProvider{
 					Provider: &esv1alpha1.SecretStoreProvider{
-						AWSSM: &esv1alpha1.AWSSMProvider{
-							Auth: &esv1alpha1.AWSSMAuth{
-								SecretRef: esv1alpha1.AWSSMAuthSecretRef{
+						AWS: &esv1alpha1.AWSProvider{
+							Auth: &esv1alpha1.AWSAuth{
+								SecretRef: esv1alpha1.AWSAuthSecretRef{
 									AccessKeyID: esmeta.SecretKeySelector{
 									AccessKeyID: esmeta.SecretKeySelector{
 										Name: "brokensecret",
 										Name: "brokensecret",
 										Key:  "one",
 										Key:  "one",
@@ -227,9 +227,9 @@ func TestConstructor(t *testing.T) {
 			store: &esv1alpha1.SecretStore{
 			store: &esv1alpha1.SecretStore{
 				Spec: esv1alpha1.SecretStoreSpec{
 				Spec: esv1alpha1.SecretStoreSpec{
 					Provider: &esv1alpha1.SecretStoreProvider{
 					Provider: &esv1alpha1.SecretStoreProvider{
-						AWSSM: &esv1alpha1.AWSSMProvider{
-							Auth: &esv1alpha1.AWSSMAuth{
-								SecretRef: esv1alpha1.AWSSMAuthSecretRef{
+						AWS: &esv1alpha1.AWSProvider{
+							Auth: &esv1alpha1.AWSAuth{
+								SecretRef: esv1alpha1.AWSAuthSecretRef{
 									AccessKeyID: esmeta.SecretKeySelector{
 									AccessKeyID: esmeta.SecretKeySelector{
 										Name:      "onesecret",
 										Name:      "onesecret",
 										Namespace: aws.String("evil"), // this should not be possible!
 										Namespace: aws.String("evil"), // this should not be possible!
@@ -270,9 +270,9 @@ func TestConstructor(t *testing.T) {
 				},
 				},
 				Spec: esv1alpha1.SecretStoreSpec{
 				Spec: esv1alpha1.SecretStoreSpec{
 					Provider: &esv1alpha1.SecretStoreProvider{
 					Provider: &esv1alpha1.SecretStoreProvider{
-						AWSSM: &esv1alpha1.AWSSMProvider{
-							Auth: &esv1alpha1.AWSSMAuth{
-								SecretRef: esv1alpha1.AWSSMAuthSecretRef{
+						AWS: &esv1alpha1.AWSProvider{
+							Auth: &esv1alpha1.AWSAuth{
+								SecretRef: esv1alpha1.AWSAuthSecretRef{
 									AccessKeyID: esmeta.SecretKeySelector{
 									AccessKeyID: esmeta.SecretKeySelector{
 										Name:      "onesecret",
 										Name:      "onesecret",
 										Namespace: aws.String("platform-team-ns"),
 										Namespace: aws.String("platform-team-ns"),
@@ -315,9 +315,9 @@ func TestConstructor(t *testing.T) {
 				},
 				},
 				Spec: esv1alpha1.SecretStoreSpec{
 				Spec: esv1alpha1.SecretStoreSpec{
 					Provider: &esv1alpha1.SecretStoreProvider{
 					Provider: &esv1alpha1.SecretStoreProvider{
-						AWSSM: &esv1alpha1.AWSSMProvider{
-							Auth: &esv1alpha1.AWSSMAuth{
-								SecretRef: esv1alpha1.AWSSMAuthSecretRef{
+						AWS: &esv1alpha1.AWSProvider{
+							Auth: &esv1alpha1.AWSAuth{
+								SecretRef: esv1alpha1.AWSAuthSecretRef{
 									AccessKeyID: esmeta.SecretKeySelector{
 									AccessKeyID: esmeta.SecretKeySelector{
 										Name: "onesecret",
 										Name: "onesecret",
 										Key:  "one",
 										Key:  "one",
@@ -397,7 +397,7 @@ func TestSMEnvCredentials(t *testing.T) {
 		Spec: esv1alpha1.SecretStoreSpec{
 		Spec: esv1alpha1.SecretStoreSpec{
 			Provider: &esv1alpha1.SecretStoreProvider{
 			Provider: &esv1alpha1.SecretStoreProvider{
 				// defaults
 				// defaults
-				AWSSM: &esv1alpha1.AWSSMProvider{},
+				AWS: &esv1alpha1.AWSProvider{},
 			},
 			},
 		},
 		},
 	}, k8sClient, "example-ns", awssess.DefaultSTSProvider)
 	}, k8sClient, "example-ns", awssess.DefaultSTSProvider)
@@ -439,7 +439,7 @@ func TestSMAssumeRole(t *testing.T) {
 		Spec: esv1alpha1.SecretStoreSpec{
 		Spec: esv1alpha1.SecretStoreSpec{
 			Provider: &esv1alpha1.SecretStoreProvider{
 			Provider: &esv1alpha1.SecretStoreProvider{
 				// do assume role!
 				// do assume role!
-				AWSSM: &esv1alpha1.AWSSMProvider{
+				AWS: &esv1alpha1.AWSProvider{
 					Role: "my-awesome-role",
 					Role: "my-awesome-role",
 				},
 				},
 			},
 			},

+ 86 - 9
pkg/provider/schema/schema_test.go

@@ -41,25 +41,102 @@ func (p *PP) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretData
 	return map[string][]byte{}, nil
 	return map[string][]byte{}, nil
 }
 }
 
 
+// TestRegister tests if the Register function
+// (1) panics if it tries to register something invalid
+// (2) stores the correct provider.
 func TestRegister(t *testing.T) {
 func TestRegister(t *testing.T) {
-	p, ok := GetProviderByName("awssm")
-	assert.Nil(t, p)
-	assert.False(t, ok, "provider should not be registered")
+	tbl := []struct {
+		test      string
+		name      string
+		expPanic  bool
+		expExists bool
+		provider  *esv1alpha1.SecretStoreProvider
+	}{
+		{
+			test:      "should panic when given an invalid provider",
+			name:      "aws",
+			expPanic:  true,
+			expExists: false,
+			provider:  &esv1alpha1.SecretStoreProvider{},
+		},
+		{
+			test:      "should register an correct provider",
+			name:      "aws",
+			expExists: false,
+			provider: &esv1alpha1.SecretStoreProvider{
+				AWS: &esv1alpha1.AWSProvider{
+					Service: esv1alpha1.AWSServiceSecretsManager,
+				},
+			},
+		},
+		{
+			test:      "should panic if already exists",
+			name:      "aws",
+			expPanic:  true,
+			expExists: true,
+			provider: &esv1alpha1.SecretStoreProvider{
+				AWS: &esv1alpha1.AWSProvider{
+					Service: esv1alpha1.AWSServiceSecretsManager,
+				},
+			},
+		},
+	}
+	for i := range tbl {
+		row := tbl[i]
+		t.Run(row.test, func(t *testing.T) {
+			runTest(t,
+				row.name,
+				row.provider,
+				row.expPanic,
+			)
+		})
+	}
+}
 
 
+func runTest(t *testing.T, name string, provider *esv1alpha1.SecretStoreProvider, expPanic bool) {
 	testProvider := &PP{}
 	testProvider := &PP{}
 	secretStore := &esv1alpha1.SecretStore{
 	secretStore := &esv1alpha1.SecretStore{
 		Spec: esv1alpha1.SecretStoreSpec{
 		Spec: esv1alpha1.SecretStoreSpec{
-			Provider: &esv1alpha1.SecretStoreProvider{
-				AWSSM: &esv1alpha1.AWSSMProvider{},
-			},
+			Provider: provider,
 		},
 		},
 	}
 	}
-
-	ForceRegister(testProvider, secretStore.Spec.Provider)
-	p1, ok := GetProviderByName("awssm")
+	if expPanic {
+		defer func() {
+			if r := recover(); r == nil {
+				t.Errorf("Register should panic")
+			}
+		}()
+	}
+	Register(testProvider, secretStore.Spec.Provider)
+	p1, ok := GetProviderByName(name)
 	assert.True(t, ok, "provider should be registered")
 	assert.True(t, ok, "provider should be registered")
 	assert.Equal(t, testProvider, p1)
 	assert.Equal(t, testProvider, p1)
+	p2, err := GetProvider(secretStore)
+	assert.Nil(t, err)
+	assert.Equal(t, testProvider, p2)
+}
 
 
+// ForceRegister is used by other tests, we should ensure it works as expected.
+func TestForceRegister(t *testing.T) {
+	testProvider := &PP{}
+	provider := &esv1alpha1.SecretStoreProvider{
+		AWS: &esv1alpha1.AWSProvider{
+			Service: esv1alpha1.AWSServiceParameterStore,
+		},
+	}
+	secretStore := &esv1alpha1.SecretStore{
+		Spec: esv1alpha1.SecretStoreSpec{
+			Provider: provider,
+		},
+	}
+	ForceRegister(testProvider, &esv1alpha1.SecretStoreProvider{
+		AWS: &esv1alpha1.AWSProvider{
+			Service: esv1alpha1.AWSServiceParameterStore,
+		},
+	})
+	p1, ok := GetProviderByName("aws")
+	assert.True(t, ok, "provider should be registered")
+	assert.Equal(t, testProvider, p1)
 	p2, err := GetProvider(secretStore)
 	p2, err := GetProvider(secretStore)
 	assert.Nil(t, err)
 	assert.Nil(t, err)
 	assert.Equal(t, testProvider, p2)
 	assert.Equal(t, testProvider, p2)