mirror of
https://github.com/external-secrets/external-secrets.git
synced 2024-12-15 17:51:01 +00:00
ADD sdkms base implementation (#3180)
* ADD sdkms base implementation Signed-off-by: Recuenco, David <david.recuenco@adidas-group.com> * FIX get secret object by name, unmarshalling error formatting Signed-off-by: Recuenco, David <david.recuenco@adidas-group.com> * ADD suport for fortanix secret security objects Signed-off-by: Recuenco, David <david.recuenco@adidas-group.com> * ADD more tests for opaque, secret, new client Signed-off-by: Recuenco, David <david.recuenco@adidas-group.com> * FIX changes required by make reviewable Signed-off-by: Recuenco, David <david.recuenco@adidas-group.com> * ADD missing provider registration Signed-off-by: Recuenco, David <david.recuenco@adidas-group.com> * FIX remove unused error string, add generated assets Signed-off-by: Recuenco, David <david.recuenco@adidas-group.com> --------- Signed-off-by: Recuenco, David <david.recuenco@adidas-group.com>
This commit is contained in:
parent
983488ca57
commit
af38fc68d5
15 changed files with 931 additions and 0 deletions
29
apis/externalsecrets/v1beta1/secretstore_fortanix_types.go
Normal file
29
apis/externalsecrets/v1beta1/secretstore_fortanix_types.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
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 v1beta1
|
||||||
|
|
||||||
|
import esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
||||||
|
|
||||||
|
type FortanixProvider struct {
|
||||||
|
// APIURL is the URL of SDKMS API. Defaults to `sdkms.fortanix.com`.
|
||||||
|
APIURL string `json:"apiUrl,omitempty"`
|
||||||
|
|
||||||
|
// APIKey is the API token to access SDKMS Applications.
|
||||||
|
APIKey *FortanixProviderSecretRef `json:"apiKey,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FortanixProviderSecretRef struct {
|
||||||
|
// SecretRef is a reference to a secret containing the SDKMS API Key.
|
||||||
|
SecretRef *esmeta.SecretKeySelector `json:"secretRef,omitempty"`
|
||||||
|
}
|
|
@ -149,6 +149,10 @@ type SecretStoreProvider struct {
|
||||||
// Pulumi configures this store to sync secrets using the Pulumi provider
|
// Pulumi configures this store to sync secrets using the Pulumi provider
|
||||||
// +optional
|
// +optional
|
||||||
Pulumi *PulumiProvider `json:"pulumi,omitempty"`
|
Pulumi *PulumiProvider `json:"pulumi,omitempty"`
|
||||||
|
|
||||||
|
// Fortanix configures this store to sync secrets using the Fortanix provider
|
||||||
|
// +optional
|
||||||
|
Fortanix *FortanixProvider `json:"fortanix,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CAProviderType string
|
type CAProviderType string
|
||||||
|
|
|
@ -1375,6 +1375,46 @@ func (in *FindName) DeepCopy() *FindName {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *FortanixProvider) DeepCopyInto(out *FortanixProvider) {
|
||||||
|
*out = *in
|
||||||
|
if in.APIKey != nil {
|
||||||
|
in, out := &in.APIKey, &out.APIKey
|
||||||
|
*out = new(FortanixProviderSecretRef)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FortanixProvider.
|
||||||
|
func (in *FortanixProvider) DeepCopy() *FortanixProvider {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(FortanixProvider)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *FortanixProviderSecretRef) DeepCopyInto(out *FortanixProviderSecretRef) {
|
||||||
|
*out = *in
|
||||||
|
if in.SecretRef != nil {
|
||||||
|
in, out := &in.SecretRef, &out.SecretRef
|
||||||
|
*out = new(metav1.SecretKeySelector)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FortanixProviderSecretRef.
|
||||||
|
func (in *FortanixProviderSecretRef) DeepCopy() *FortanixProviderSecretRef {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(FortanixProviderSecretRef)
|
||||||
|
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 *GCPSMAuth) DeepCopyInto(out *GCPSMAuth) {
|
func (in *GCPSMAuth) DeepCopyInto(out *GCPSMAuth) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -2094,6 +2134,11 @@ func (in *SecretStoreProvider) DeepCopyInto(out *SecretStoreProvider) {
|
||||||
*out = new(PulumiProvider)
|
*out = new(PulumiProvider)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
|
if in.Fortanix != nil {
|
||||||
|
in, out := &in.Fortanix, &out.Fortanix
|
||||||
|
*out = new(FortanixProvider)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretStoreProvider.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretStoreProvider.
|
||||||
|
|
|
@ -2574,6 +2574,37 @@ spec:
|
||||||
required:
|
required:
|
||||||
- data
|
- data
|
||||||
type: object
|
type: object
|
||||||
|
fortanix:
|
||||||
|
description: Fortanix configures this store to sync secrets using
|
||||||
|
the Fortanix provider
|
||||||
|
properties:
|
||||||
|
apiKey:
|
||||||
|
description: APIKey is the API token to access SDKMS Applications.
|
||||||
|
properties:
|
||||||
|
secretRef:
|
||||||
|
description: SecretRef is a reference to a secret containing
|
||||||
|
the SDKMS API Key.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: |-
|
||||||
|
The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be
|
||||||
|
defaulted, in others it may be required.
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: The name of the Secret resource being
|
||||||
|
referred to.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: |-
|
||||||
|
Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults
|
||||||
|
to the namespace of the referent.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
apiUrl:
|
||||||
|
description: APIURL is the URL of SDKMS API. Defaults to `sdkms.fortanix.com`.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
gcpsm:
|
gcpsm:
|
||||||
description: GCPSM configures this store to sync secrets using
|
description: GCPSM configures this store to sync secrets using
|
||||||
Google Cloud Platform Secret Manager provider
|
Google Cloud Platform Secret Manager provider
|
||||||
|
|
|
@ -2574,6 +2574,37 @@ spec:
|
||||||
required:
|
required:
|
||||||
- data
|
- data
|
||||||
type: object
|
type: object
|
||||||
|
fortanix:
|
||||||
|
description: Fortanix configures this store to sync secrets using
|
||||||
|
the Fortanix provider
|
||||||
|
properties:
|
||||||
|
apiKey:
|
||||||
|
description: APIKey is the API token to access SDKMS Applications.
|
||||||
|
properties:
|
||||||
|
secretRef:
|
||||||
|
description: SecretRef is a reference to a secret containing
|
||||||
|
the SDKMS API Key.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: |-
|
||||||
|
The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be
|
||||||
|
defaulted, in others it may be required.
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: The name of the Secret resource being
|
||||||
|
referred to.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: |-
|
||||||
|
Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults
|
||||||
|
to the namespace of the referent.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
apiUrl:
|
||||||
|
description: APIURL is the URL of SDKMS API. Defaults to `sdkms.fortanix.com`.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
gcpsm:
|
gcpsm:
|
||||||
description: GCPSM configures this store to sync secrets using
|
description: GCPSM configures this store to sync secrets using
|
||||||
Google Cloud Platform Secret Manager provider
|
Google Cloud Platform Secret Manager provider
|
||||||
|
|
|
@ -3007,6 +3007,34 @@ spec:
|
||||||
required:
|
required:
|
||||||
- data
|
- data
|
||||||
type: object
|
type: object
|
||||||
|
fortanix:
|
||||||
|
description: Fortanix configures this store to sync secrets using the Fortanix provider
|
||||||
|
properties:
|
||||||
|
apiKey:
|
||||||
|
description: APIKey is the API token to access SDKMS Applications.
|
||||||
|
properties:
|
||||||
|
secretRef:
|
||||||
|
description: SecretRef is a reference to a secret containing the SDKMS API Key.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: |-
|
||||||
|
The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be
|
||||||
|
defaulted, in others it may be required.
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: The name of the Secret resource being referred to.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: |-
|
||||||
|
Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults
|
||||||
|
to the namespace of the referent.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
apiUrl:
|
||||||
|
description: APIURL is the URL of SDKMS API. Defaults to `sdkms.fortanix.com`.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
gcpsm:
|
gcpsm:
|
||||||
description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider
|
description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider
|
||||||
properties:
|
properties:
|
||||||
|
@ -8069,6 +8097,34 @@ spec:
|
||||||
required:
|
required:
|
||||||
- data
|
- data
|
||||||
type: object
|
type: object
|
||||||
|
fortanix:
|
||||||
|
description: Fortanix configures this store to sync secrets using the Fortanix provider
|
||||||
|
properties:
|
||||||
|
apiKey:
|
||||||
|
description: APIKey is the API token to access SDKMS Applications.
|
||||||
|
properties:
|
||||||
|
secretRef:
|
||||||
|
description: SecretRef is a reference to a secret containing the SDKMS API Key.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: |-
|
||||||
|
The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be
|
||||||
|
defaulted, in others it may be required.
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: The name of the Secret resource being referred to.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: |-
|
||||||
|
Namespace of the resource being referred to. Ignored if referent is not cluster-scoped. cluster-scoped defaults
|
||||||
|
to the namespace of the referent.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
apiUrl:
|
||||||
|
description: APIURL is the URL of SDKMS API. Defaults to `sdkms.fortanix.com`.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
gcpsm:
|
gcpsm:
|
||||||
description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider
|
description: GCPSM configures this store to sync secrets using Google Cloud Platform Secret Manager provider
|
||||||
properties:
|
properties:
|
||||||
|
|
|
@ -3658,6 +3658,79 @@ string
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<h3 id="external-secrets.io/v1beta1.FortanixProvider">FortanixProvider
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
(<em>Appears on:</em>
|
||||||
|
<a href="#external-secrets.io/v1beta1.SecretStoreProvider">SecretStoreProvider</a>)
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
</p>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Field</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>apiUrl</code></br>
|
||||||
|
<em>
|
||||||
|
string
|
||||||
|
</em>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<p>APIURL is the URL of SDKMS API. Defaults to <code>sdkms.fortanix.com</code>.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>apiKey</code></br>
|
||||||
|
<em>
|
||||||
|
<a href="#external-secrets.io/v1beta1.FortanixProviderSecretRef">
|
||||||
|
FortanixProviderSecretRef
|
||||||
|
</a>
|
||||||
|
</em>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<p>APIKey is the API token to access SDKMS Applications.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<h3 id="external-secrets.io/v1beta1.FortanixProviderSecretRef">FortanixProviderSecretRef
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
(<em>Appears on:</em>
|
||||||
|
<a href="#external-secrets.io/v1beta1.FortanixProvider">FortanixProvider</a>)
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
</p>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Field</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>secretRef</code></br>
|
||||||
|
<em>
|
||||||
|
<a href="https://pkg.go.dev/github.com/external-secrets/external-secrets/apis/meta/v1#SecretKeySelector">
|
||||||
|
External Secrets meta/v1.SecretKeySelector
|
||||||
|
</a>
|
||||||
|
</em>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<p>SecretRef is a reference to a secret containing the SDKMS API Key.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
<h3 id="external-secrets.io/v1beta1.GCPSMAuth">GCPSMAuth
|
<h3 id="external-secrets.io/v1beta1.GCPSMAuth">GCPSMAuth
|
||||||
</h3>
|
</h3>
|
||||||
<p>
|
<p>
|
||||||
|
@ -5533,6 +5606,20 @@ PulumiProvider
|
||||||
<p>Pulumi configures this store to sync secrets using the Pulumi provider</p>
|
<p>Pulumi configures this store to sync secrets using the Pulumi provider</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>fortanix</code></br>
|
||||||
|
<em>
|
||||||
|
<a href="#external-secrets.io/v1beta1.FortanixProvider">
|
||||||
|
FortanixProvider
|
||||||
|
</a>
|
||||||
|
</em>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<em>(Optional)</em>
|
||||||
|
<p>Fortanix configures this store to sync secrets using the Fortanix provider</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<h3 id="external-secrets.io/v1beta1.SecretStoreRef">SecretStoreRef
|
<h3 id="external-secrets.io/v1beta1.SecretStoreRef">SecretStoreRef
|
||||||
|
|
50
docs/provider/fortanix.md
Normal file
50
docs/provider/fortanix.md
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
## Fortanix DSM / SDKMS
|
||||||
|
|
||||||
|
Populate kubernetes secrets from OPAQUE or SECRET security objects in Fortanix.
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
|
||||||
|
SDKMS [Application API Key](https://support.fortanix.com/hc/en-us/articles/360015941132-Authentication)
|
||||||
|
|
||||||
|
### Creating a SecretStore
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: external-secrets.io/v1beta1
|
||||||
|
kind: SecretStore
|
||||||
|
metadata:
|
||||||
|
name: secret-store
|
||||||
|
spec:
|
||||||
|
provider:
|
||||||
|
fortanix:
|
||||||
|
apiUrl: <HOST_OF_SDKMS_API>
|
||||||
|
apiKey:
|
||||||
|
secretRef:
|
||||||
|
name: <NAME_OF_KUBE_SECRET>
|
||||||
|
key: <KEY_IN_KUBE_SECRET>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Referencing Secrets
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: external-secrets.io/v1beta1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: secret
|
||||||
|
spec:
|
||||||
|
refreshInterval: 1h
|
||||||
|
secretStoreRef:
|
||||||
|
kind: SecretStore
|
||||||
|
name: secret-store
|
||||||
|
data:
|
||||||
|
|
||||||
|
# Raw stored value
|
||||||
|
- secretKey: <KEY_IN_KUBE_SECRET>
|
||||||
|
remoteRef:
|
||||||
|
key: <SDKMS_SECURITY_OBJECT_NAME>
|
||||||
|
|
||||||
|
# From stored key-value JSON
|
||||||
|
- secretKey: <KEY_IN_KUBE_SECRET>
|
||||||
|
remoteRef:
|
||||||
|
key: <SDKMS_SECURITY_OBJECT_NAME>
|
||||||
|
property: <SECURITY_OBJECT_VALUE_INNER_PROPERTY>
|
||||||
|
```
|
1
go.mod
1
go.mod
|
@ -72,6 +72,7 @@ require (
|
||||||
github.com/aliyun/credentials-go v1.3.2
|
github.com/aliyun/credentials-go v1.3.2
|
||||||
github.com/avast/retry-go/v4 v4.5.1
|
github.com/avast/retry-go/v4 v4.5.1
|
||||||
github.com/cyberark/conjur-api-go v0.11.1
|
github.com/cyberark/conjur-api-go v0.11.1
|
||||||
|
github.com/fortanix/sdkms-client-go v0.4.0
|
||||||
github.com/go-openapi/strfmt v0.22.0
|
github.com/go-openapi/strfmt v0.22.0
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.0
|
github.com/golang-jwt/jwt/v5 v5.2.0
|
||||||
github.com/hashicorp/golang-lru v1.0.2
|
github.com/hashicorp/golang-lru v1.0.2
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -288,6 +288,8 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
|
github.com/fortanix/sdkms-client-go v0.4.0 h1:5cKiFJ4rzc69mhsVVI5Ma5ynr/k5vhvws0yfzfIro/k=
|
||||||
|
github.com/fortanix/sdkms-client-go v0.4.0/go.mod h1:gjylIGX+6poVSe+JkbNsLTvseLd+rLjvcGFgXpW56Lo=
|
||||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
|
|
99
pkg/provider/fortanix/fortanix.go
Normal file
99
pkg/provider/fortanix/fortanix.go
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
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 fortanix
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/fortanix/sdkms-client-go/sdkms"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
|
||||||
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type client struct {
|
||||||
|
sdkms sdkms.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
errPushSecretsNotSupported = "pushing secrets is currently not supported"
|
||||||
|
errDeleteSecretsNotSupported = "deleting secrets is currently not supported"
|
||||||
|
errUnmarshalSecret = "unable to unmarshal secret, is it a valid JSON?: %w"
|
||||||
|
errUnableToGetValue = "unable to get value for key %s"
|
||||||
|
errGettingSecretMapNotSupported = "getting secret map is currently not supported"
|
||||||
|
errGettingAllSecretsNotSupported = "getting all secrets is currently not supported"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *client) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
|
||||||
|
securityObject, err := c.sdkms.GetSobject(ctx, &sdkms.GetSobjectParams{}, *sdkms.SobjectByName(ref.Key))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if securityObject.ObjType == sdkms.ObjectTypeSecret {
|
||||||
|
securityObject, err = c.sdkms.ExportSobject(ctx, *sdkms.SobjectByID(*securityObject.Kid))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ref.Property == "" {
|
||||||
|
return *securityObject.Value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
kv := make(map[string]string)
|
||||||
|
|
||||||
|
err = json.Unmarshal(*securityObject.Value, &kv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(errUnmarshalSecret, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
value, ok := kv[ref.Property]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf(errUnableToGetValue, ref.Property)
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils.GetByteValue(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) PushSecret(_ context.Context, _ *corev1.Secret, _ esv1beta1.PushSecretData) error {
|
||||||
|
return errors.New(errPushSecretsNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) DeleteSecret(_ context.Context, _ esv1beta1.PushSecretRemoteRef) error {
|
||||||
|
return errors.New(errDeleteSecretsNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) Validate() (esv1beta1.ValidationResult, error) {
|
||||||
|
return esv1beta1.ValidationResultReady, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) GetSecretMap(_ context.Context, _ esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
|
||||||
|
return nil, errors.New(errGettingSecretMapNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) GetAllSecrets(_ context.Context, _ esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
|
||||||
|
return nil, errors.New(errGettingAllSecretsNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) Close(context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
152
pkg/provider/fortanix/fortanix_test.go
Normal file
152
pkg/provider/fortanix/fortanix_test.go
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
/*
|
||||||
|
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 fortanix
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/fortanix/sdkms-client-go/sdkms"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newTestClient(t *testing.T, handler func(w http.ResponseWriter, r *http.Request)) *client {
|
||||||
|
const apiKey = "api-key"
|
||||||
|
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
handler(w, r)
|
||||||
|
}))
|
||||||
|
t.Cleanup(server.Close)
|
||||||
|
|
||||||
|
return &client{
|
||||||
|
sdkms: sdkms.Client{
|
||||||
|
HTTPClient: http.DefaultClient,
|
||||||
|
Auth: sdkms.APIKey(apiKey),
|
||||||
|
Endpoint: server.URL,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toJSON(t *testing.T, v interface{}) []byte {
|
||||||
|
jsonBytes, err := json.Marshal(v)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
return jsonBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
type testSecurityObjectValue struct {
|
||||||
|
Property string `json:"property"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetOpaqueSecurityObject(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
securityObjectName := "securityObjectName"
|
||||||
|
|
||||||
|
securityObjectValue := toJSON(t, testSecurityObjectValue{
|
||||||
|
Property: "value",
|
||||||
|
})
|
||||||
|
|
||||||
|
securityObjectUser := "user"
|
||||||
|
|
||||||
|
securityObject := sdkms.Sobject{
|
||||||
|
Creator: sdkms.Principal{
|
||||||
|
User: &securityObjectUser,
|
||||||
|
},
|
||||||
|
Name: &securityObjectName,
|
||||||
|
Value: &securityObjectValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
client := newTestClient(t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
err := json.NewEncoder(w).Encode(securityObject)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("get raw secret value from opaque security object", func(t *testing.T) {
|
||||||
|
ref := esv1beta1.ExternalSecretDataRemoteRef{
|
||||||
|
Key: securityObjectName,
|
||||||
|
}
|
||||||
|
|
||||||
|
got, err := client.GetSecret(ctx, ref)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, securityObjectValue, got)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("get inner property value from opaque security object", func(t *testing.T) {
|
||||||
|
ref := esv1beta1.ExternalSecretDataRemoteRef{
|
||||||
|
Key: securityObjectName,
|
||||||
|
Property: "property",
|
||||||
|
}
|
||||||
|
|
||||||
|
got, err := client.GetSecret(ctx, ref)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []byte(`value`), got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetSecretSecurityObject(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
securityObjectName := "securityObjectName"
|
||||||
|
securityObjectID := "id"
|
||||||
|
|
||||||
|
securityObjectValue := toJSON(t, testSecurityObjectValue{
|
||||||
|
Property: "value",
|
||||||
|
})
|
||||||
|
|
||||||
|
securityObjectUser := "user"
|
||||||
|
|
||||||
|
securityObject := sdkms.Sobject{
|
||||||
|
Creator: sdkms.Principal{
|
||||||
|
User: &securityObjectUser,
|
||||||
|
},
|
||||||
|
Name: &securityObjectName,
|
||||||
|
Kid: &securityObjectID,
|
||||||
|
Value: &securityObjectValue,
|
||||||
|
ObjType: sdkms.ObjectTypeSecret,
|
||||||
|
}
|
||||||
|
|
||||||
|
client := newTestClient(t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
err := json.NewEncoder(w).Encode(securityObject)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("get raw secret value from secret security object", func(t *testing.T) {
|
||||||
|
ref := esv1beta1.ExternalSecretDataRemoteRef{
|
||||||
|
Key: securityObjectName,
|
||||||
|
}
|
||||||
|
|
||||||
|
got, err := client.GetSecret(ctx, ref)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, securityObjectValue, got)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("get inner property value from secret security object", func(t *testing.T) {
|
||||||
|
ref := esv1beta1.ExternalSecretDataRemoteRef{
|
||||||
|
Key: securityObjectName,
|
||||||
|
Property: "property",
|
||||||
|
}
|
||||||
|
|
||||||
|
got, err := client.GetSecret(ctx, ref)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []byte(`value`), got)
|
||||||
|
})
|
||||||
|
}
|
124
pkg/provider/fortanix/provider.go
Normal file
124
pkg/provider/fortanix/provider.go
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
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 fortanix
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/fortanix/sdkms-client-go/sdkms"
|
||||||
|
kubeclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||||
|
|
||||||
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils"
|
||||||
|
"github.com/external-secrets/external-secrets/pkg/utils/resolvers"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Provider struct{}
|
||||||
|
|
||||||
|
const (
|
||||||
|
errCannotResolveSecretKeyRef = "cannot resolve secret key ref: %w"
|
||||||
|
errStoreIsNil = "store is nil"
|
||||||
|
errNoStoreTypeOrWrongStoreType = "no store type or wrong store type"
|
||||||
|
errAPIKeyIsRequired = "apiKey is required"
|
||||||
|
errAPIKeySecretRefIsRequired = "apiKey.secretRef is required"
|
||||||
|
errAPIKeySecretRefNameIsRequired = "apiKey.secretRef.name is required"
|
||||||
|
errAPIKeySecretRefKeyIsRequired = "apiKey.secretRef.key is required"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ esv1beta1.Provider = &Provider{}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
esv1beta1.Register(&Provider{}, &esv1beta1.SecretStoreProvider{
|
||||||
|
Fortanix: &esv1beta1.FortanixProvider{},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Provider) Capabilities() esv1beta1.SecretStoreCapabilities {
|
||||||
|
return esv1beta1.SecretStoreReadOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Provider) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kubeclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
|
||||||
|
config, err := getConfig(store)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
apiKey, err := resolvers.SecretKeyRef(ctx, kube, store.GetKind(), namespace, config.APIKey.SecretRef)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(errCannotResolveSecretKeyRef, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sdkmsClient := sdkms.Client{
|
||||||
|
HTTPClient: http.DefaultClient,
|
||||||
|
Auth: sdkms.APIKey(apiKey),
|
||||||
|
Endpoint: config.APIURL,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &client{
|
||||||
|
sdkms: sdkmsClient,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Provider) ValidateStore(store esv1beta1.GenericStore) (admission.Warnings, error) {
|
||||||
|
_, err := getConfig(store)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func getConfig(store esv1beta1.GenericStore) (*esv1beta1.FortanixProvider, error) {
|
||||||
|
if store == nil {
|
||||||
|
return nil, errors.New(errStoreIsNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
spec := store.GetSpec()
|
||||||
|
if spec == nil || spec.Provider == nil || spec.Provider.Fortanix == nil {
|
||||||
|
return nil, errors.New(errNoStoreTypeOrWrongStoreType)
|
||||||
|
}
|
||||||
|
|
||||||
|
config := spec.Provider.Fortanix
|
||||||
|
|
||||||
|
if config.APIURL == "" {
|
||||||
|
config.APIURL = "https://sdkms.fortanix.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
err := validateSecretStoreRef(store, config.APIKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateSecretStoreRef(store esv1beta1.GenericStore, ref *esv1beta1.FortanixProviderSecretRef) error {
|
||||||
|
if ref == nil {
|
||||||
|
return errors.New(errAPIKeyIsRequired)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ref.SecretRef == nil {
|
||||||
|
return errors.New(errAPIKeySecretRefIsRequired)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ref.SecretRef.Name == "" {
|
||||||
|
return errors.New(errAPIKeySecretRefNameIsRequired)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ref.SecretRef.Key == "" {
|
||||||
|
return errors.New(errAPIKeySecretRefKeyIsRequired)
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils.ValidateReferentSecretSelector(store, *ref.SecretRef)
|
||||||
|
}
|
219
pkg/provider/fortanix/provider_test.go
Normal file
219
pkg/provider/fortanix/provider_test.go
Normal file
|
@ -0,0 +1,219 @@
|
||||||
|
/*
|
||||||
|
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 fortanix
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
|
kubeclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||||
|
v1 "github.com/external-secrets/external-secrets/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func pointer[T any](d T) *T {
|
||||||
|
return &d
|
||||||
|
}
|
||||||
|
|
||||||
|
func respondJSON(w http.ResponseWriter, data interface{}) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
json.NewEncoder(w).Encode(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createMockKubernetesClient(t *testing.T) kubeclient.Client {
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
switch r.URL.Path {
|
||||||
|
case "/api/v1":
|
||||||
|
respondJSON(w, metav1.APIResourceList{
|
||||||
|
APIResources: []metav1.APIResource{
|
||||||
|
{
|
||||||
|
Name: "secrets",
|
||||||
|
Namespaced: true,
|
||||||
|
Kind: "Secret",
|
||||||
|
Verbs: metav1.Verbs{
|
||||||
|
"get",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
case "/api/v1/namespaces/test/secrets/secret-name":
|
||||||
|
respondJSON(w, corev1.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "secret-name",
|
||||||
|
},
|
||||||
|
Data: map[string][]byte{
|
||||||
|
"apiKey": []byte("apiKey"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
case "/api/v1/namespaces/test/secrets/missing-secret":
|
||||||
|
w.WriteHeader(404)
|
||||||
|
respondJSON(w, metav1.Status{
|
||||||
|
Code: 404,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
t.Cleanup(server.Close)
|
||||||
|
|
||||||
|
clientConfig := clientcmd.NewDefaultClientConfig(clientcmdapi.Config{
|
||||||
|
Clusters: map[string]*clientcmdapi.Cluster{
|
||||||
|
"test": {
|
||||||
|
Server: server.URL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
||||||
|
"test": {
|
||||||
|
Token: "token",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Contexts: map[string]*clientcmdapi.Context{
|
||||||
|
"test": {
|
||||||
|
Cluster: "test",
|
||||||
|
AuthInfo: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CurrentContext: "test",
|
||||||
|
}, &clientcmd.ConfigOverrides{})
|
||||||
|
|
||||||
|
restConfig, err := clientConfig.ClientConfig()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
c, err := kubeclient.New(restConfig, kubeclient.Options{})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewClient(t *testing.T) {
|
||||||
|
t.Run("should create new client", func(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
p := &Provider{}
|
||||||
|
c := createMockKubernetesClient(t)
|
||||||
|
s := esv1beta1.SecretStore{
|
||||||
|
Spec: esv1beta1.SecretStoreSpec{
|
||||||
|
Provider: &esv1beta1.SecretStoreProvider{
|
||||||
|
Fortanix: &esv1beta1.FortanixProvider{
|
||||||
|
APIKey: &esv1beta1.FortanixProviderSecretRef{
|
||||||
|
SecretRef: &v1.SecretKeySelector{
|
||||||
|
Name: "secret-name",
|
||||||
|
Key: "apiKey",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := p.NewClient(ctx, &s, c, "test")
|
||||||
|
|
||||||
|
assert.Nil(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should fail to create new client if secret is missing", func(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
p := &Provider{}
|
||||||
|
c := createMockKubernetesClient(t)
|
||||||
|
s := esv1beta1.SecretStore{
|
||||||
|
Spec: esv1beta1.SecretStoreSpec{
|
||||||
|
Provider: &esv1beta1.SecretStoreProvider{
|
||||||
|
Fortanix: &esv1beta1.FortanixProvider{
|
||||||
|
APIKey: &esv1beta1.FortanixProviderSecretRef{
|
||||||
|
SecretRef: &v1.SecretKeySelector{
|
||||||
|
Name: "missing-secret",
|
||||||
|
Key: "apiKey",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := p.NewClient(ctx, &s, c, "test")
|
||||||
|
|
||||||
|
assert.ErrorContains(t, err, "cannot resolve secret key ref")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateStore(t *testing.T) {
|
||||||
|
tests := map[string]struct {
|
||||||
|
cfg esv1beta1.FortanixProvider
|
||||||
|
want error
|
||||||
|
}{
|
||||||
|
"missing api key": {
|
||||||
|
cfg: esv1beta1.FortanixProvider{},
|
||||||
|
want: errors.New("apiKey is required"),
|
||||||
|
},
|
||||||
|
"missing api key secret ref": {
|
||||||
|
cfg: esv1beta1.FortanixProvider{
|
||||||
|
APIKey: &esv1beta1.FortanixProviderSecretRef{},
|
||||||
|
},
|
||||||
|
want: errors.New("apiKey.secretRef is required"),
|
||||||
|
},
|
||||||
|
"missing api key secret ref name": {
|
||||||
|
cfg: esv1beta1.FortanixProvider{
|
||||||
|
APIKey: &esv1beta1.FortanixProviderSecretRef{
|
||||||
|
SecretRef: &v1.SecretKeySelector{
|
||||||
|
Key: "key",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: errors.New("apiKey.secretRef.name is required"),
|
||||||
|
},
|
||||||
|
"missing api key secret ref key": {
|
||||||
|
cfg: esv1beta1.FortanixProvider{
|
||||||
|
APIKey: &esv1beta1.FortanixProviderSecretRef{
|
||||||
|
SecretRef: &v1.SecretKeySelector{
|
||||||
|
Name: "name",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: errors.New("apiKey.secretRef.key is required"),
|
||||||
|
},
|
||||||
|
"disallowed namespace in store ref": {
|
||||||
|
cfg: esv1beta1.FortanixProvider{
|
||||||
|
APIKey: &esv1beta1.FortanixProviderSecretRef{
|
||||||
|
SecretRef: &v1.SecretKeySelector{
|
||||||
|
Key: "key",
|
||||||
|
Name: "name",
|
||||||
|
Namespace: pointer("namespace"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: errors.New("namespace not allowed with namespaced SecretStore"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for name, tc := range tests {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
s := esv1beta1.SecretStore{
|
||||||
|
Spec: esv1beta1.SecretStoreSpec{
|
||||||
|
Provider: &esv1beta1.SecretStoreProvider{
|
||||||
|
Fortanix: &tc.cfg,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
p := &Provider{}
|
||||||
|
_, got := p.ValidateStore(&s)
|
||||||
|
assert.Equal(t, tc.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,7 @@ import (
|
||||||
_ "github.com/external-secrets/external-secrets/pkg/provider/delinea"
|
_ "github.com/external-secrets/external-secrets/pkg/provider/delinea"
|
||||||
_ "github.com/external-secrets/external-secrets/pkg/provider/doppler"
|
_ "github.com/external-secrets/external-secrets/pkg/provider/doppler"
|
||||||
_ "github.com/external-secrets/external-secrets/pkg/provider/fake"
|
_ "github.com/external-secrets/external-secrets/pkg/provider/fake"
|
||||||
|
_ "github.com/external-secrets/external-secrets/pkg/provider/fortanix"
|
||||||
_ "github.com/external-secrets/external-secrets/pkg/provider/gcp/secretmanager"
|
_ "github.com/external-secrets/external-secrets/pkg/provider/gcp/secretmanager"
|
||||||
_ "github.com/external-secrets/external-secrets/pkg/provider/gitlab"
|
_ "github.com/external-secrets/external-secrets/pkg/provider/gitlab"
|
||||||
_ "github.com/external-secrets/external-secrets/pkg/provider/ibm"
|
_ "github.com/external-secrets/external-secrets/pkg/provider/ibm"
|
||||||
|
|
Loading…
Reference in a new issue