Browse Source

Extract support for SDKMS provider (#3237)

* ADD extract support for sdkms provider

Signed-off-by: Recuenco, David <david.recuenco@adidas-group.com>

* Apply suggestions from code review

Co-authored-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>
Signed-off-by: David Recuenco <david.recuencogadea+github@gmail.com>

---------

Signed-off-by: Recuenco, David <david.recuenco@adidas-group.com>
Signed-off-by: David Recuenco <david.recuencogadea+github@gmail.com>
Co-authored-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>
David Recuenco 2 years ago
parent
commit
7602995a1c
3 changed files with 91 additions and 16 deletions
  1. 27 4
      docs/provider/fortanix.md
  2. 20 5
      pkg/provider/fortanix/fortanix.go
  3. 44 7
      pkg/provider/fortanix/fortanix_test.go

+ 27 - 4
docs/provider/fortanix.md

@@ -26,6 +26,7 @@ spec:
 ### Referencing Secrets
 
 ```yaml
+# Raw stored value
 apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
@@ -36,15 +37,37 @@ spec:
     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
+---
+# From stored key-value JSON
+apiVersion: external-secrets.io/v1beta1
+kind: ExternalSecret
+metadata:
+  name: secret-from-property
+spec:
+  refreshInterval: 1h
+  secretStoreRef:
+    kind: SecretStore
+    name: secret-store
+  data:
   - secretKey: <KEY_IN_KUBE_SECRET>
     remoteRef:
       key: <SDKMS_SECURITY_OBJECT_NAME>
       property: <SECURITY_OBJECT_VALUE_INNER_PROPERTY>
+---
+# Extract all keys from stored key-value JSON
+apiVersion: external-secrets.io/v1beta1
+kind: ExternalSecret
+metadata:
+  name: secret-from-extract
+spec:
+  refreshInterval: 1h
+  secretStoreRef:
+    kind: SecretStore
+    name: secret-store
+  dataFrom:
+  - extract:
+      key: <SDKMS_SECURITY_OBJECT_NAME>
 ```

+ 20 - 5
pkg/provider/fortanix/fortanix.go

@@ -35,7 +35,6 @@ const (
 	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"
 )
 
@@ -74,6 +73,26 @@ func (c *client) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretData
 	return utils.GetByteValue(value)
 }
 
+func (c *client) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
+	data, err := c.GetSecret(ctx, ref)
+	if err != nil {
+		return nil, err
+	}
+
+	kv := make(map[string]string)
+	err = json.Unmarshal(data, &kv)
+	if err != nil {
+		return nil, fmt.Errorf(errUnmarshalSecret, err)
+	}
+
+	secretData := make(map[string][]byte, len(kv))
+	for k, v := range kv {
+		secretData[k] = []byte(v)
+	}
+
+	return secretData, nil
+}
+
 func (c *client) PushSecret(_ context.Context, _ *corev1.Secret, _ esv1beta1.PushSecretData) error {
 	return errors.New(errPushSecretsNotSupported)
 }
@@ -90,10 +109,6 @@ 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)
 }

+ 44 - 7
pkg/provider/fortanix/fortanix_test.go

@@ -27,6 +27,12 @@ import (
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 )
 
+var (
+	securityObjectID   = "id"
+	securityObjectName = "securityObjectName"
+	securityObjectUser = "user"
+)
+
 func newTestClient(t *testing.T, handler func(w http.ResponseWriter, r *http.Request)) *client {
 	const apiKey = "api-key"
 
@@ -56,14 +62,11 @@ type testSecurityObjectValue struct {
 
 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,
@@ -103,15 +106,11 @@ func TestGetOpaqueSecurityObject(t *testing.T) {
 
 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,
@@ -150,3 +149,41 @@ func TestGetSecretSecurityObject(t *testing.T) {
 		assert.Equal(t, []byte(`value`), got)
 	})
 }
+
+func TestDataFromExtract(t *testing.T) {
+	ctx := context.Background()
+
+	securityObjectValue := toJSON(t, testSecurityObjectValue{
+		Property: "value",
+	})
+
+	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("extract data from secret security object", func(t *testing.T) {
+		ref := esv1beta1.ExternalSecretDataRemoteRef{
+			Key: securityObjectName,
+		}
+
+		got, err := client.GetSecretMap(ctx, ref)
+
+		assert.NoError(t, err)
+
+		for k, v := range got {
+			assert.Equal(t, "property", k)
+			assert.Equal(t, []byte(`value`), v)
+		}
+	})
+}