Browse Source

Enhance logic support . in key and returning entire payload if no property is set

Hafid.Haddouti 4 years ago
parent
commit
aed6ec295b

+ 11 - 3
docs/provider-ibm-secrets-manager.md

@@ -85,7 +85,7 @@ The behavior for the different secret types is as following:
 * `dataFrom` retrieves all `certificate`, `private_key` and `intermediate` fields from the secrets manager secret and sets appropriate key:value pairs in the resulting Kubernetes secret
 
 #### kv
-* `remoteRef` requires a `property` to select requested key from the KV secret
+* `remoteRef` could has a `property` to select requested key from the KV secret, otherwise the entire secret will be returned
 * `dataFrom` retrieves a string from secrets manager and tries to parse it as JSON object and determining the key (using gjson path) in resulting Kubernetes secret if successful
 
 ```json
@@ -95,7 +95,8 @@ The behavior for the different secret types is as following:
   "key3": {
     "keyA": "valA",
     "keyB": "valB"
-  }
+  },
+  "special.key": "special-content"
 }
 ```
 
@@ -104,9 +105,16 @@ The behavior for the different secret types is as following:
   remoteRef:
     key: 'kv/aaaaa-bbbb-cccc-dddd-eeeeee'
     property: 'key3.keyB'
+- secretKey: special_key
+  remoteRef:
+    key: 'kv/aaaaa-bbbb-cccc-dddd-eeeeee'
+    property: 'special.key'
+- secretKey: key_all
+  remoteRef:
+    key: 'kv/aaaaa-bbbb-cccc-dddd-eeeeee'
 ```
 
-results in `key3_keyB: valB`
+results in `key3_keyB: valB` and `special_key: special-content` and the `key_all` will contain the **entire** payload of the secret `{"key1":"val1","key2":"val2", ..."special.key":"special-content"}`.
 
 ### Creating external secret
 

+ 31 - 4
pkg/provider/ibm/provider.go

@@ -149,10 +149,11 @@ func (ibm *providerIBM) GetSecret(ctx context.Context, ref esv1beta1.ExternalSec
 
 	case sm.CreateSecretOptionsSecretTypeKvConst:
 
-		if ref.Property == "" {
-			return nil, fmt.Errorf("remoteRef.property required for secret type kv")
-		}
-
+		/*
+			if ref.Property == "" {
+				return nil, fmt.Errorf("remoteRef.property required for secret type kv")
+			}
+		*/
 		return getKVSecret(ibm, &secretName, ref)
 
 	default:
@@ -276,7 +277,33 @@ func getKVSecret(ibm *providerIBM, secretName *string, ref esv1beta1.ExternalSec
 		payloadJSON = string(payloadJSONByte)
 	}
 
+	// no property requested, return the entire payload
+	if ref.Property == "" {
+		return []byte(payloadJSON.(string)), nil
+	}
+
+	// returns the requested key
+	// consider that the key contains a ".". this could be one of 2 options
+	// a) "." is part of the key name
+	// b) "." is symbole for JSON path
 	if ref.Property != "" {
+
+		refProperty := ref.Property
+
+		// a) "." is part the key name
+		// escape "."
+		idx := strings.Index(refProperty, ".")
+		if idx > 0 {
+			refProperty = strings.ReplaceAll(refProperty, ".", "\\.")
+
+			val := gjson.Get(payloadJSON.(string), refProperty)
+			if val.Exists() {
+				return []byte(val.String()), nil
+			}
+		}
+
+		// b) "." is symbole for JSON path
+		// try to get value for this path
 		val := gjson.Get(payloadJSON.(string), ref.Property)
 		if !val.Exists() {
 			return nil, fmt.Errorf("key %s does not exist in secret %s", ref.Property, ref.Key)

+ 37 - 3
pkg/provider/ibm/provider_test.go

@@ -269,7 +269,7 @@ func TestIBMSecretManagerGetSecret(t *testing.T) {
 	secretDataKV["payload"] = secretKVPayload
 
 	secretDataKVComplex := make(map[string]interface{})
-	secretKVComplex := `{"key1":"val1","key2":"val2","key3":"val3","keyC":{"keyC1":"valC1", "keyC2":"valC2"}}`
+	secretKVComplex := `{"key1":"val1","key2":"val2","key3":"val3","keyC":{"keyC1":"valC1", "keyC2":"valC2"}, "special.log": "file-content"}`
 
 	secretDataKVComplex["payload"] = secretKVComplex
 
@@ -306,7 +306,7 @@ func TestIBMSecretManagerGetSecret(t *testing.T) {
 		smtc.expectedSecret = "val1"
 	}
 
-	// good case: kv type without property, returns all
+	// good case: kv type with property, returns specific value
 	setSecretKVWithKey := func(smtc *secretManagerTestCase) {
 		resources := []sm.SecretResourceIntf{
 			&sm.SecretResource{
@@ -322,7 +322,7 @@ func TestIBMSecretManagerGetSecret(t *testing.T) {
 		smtc.expectedSecret = "val2"
 	}
 
-	// good case: kv type without property, returns all
+	// good case: kv type with property and path, returns specific value
 	setSecretKVWithKeyPath := func(smtc *secretManagerTestCase) {
 		resources := []sm.SecretResourceIntf{
 			&sm.SecretResource{
@@ -338,6 +338,38 @@ func TestIBMSecretManagerGetSecret(t *testing.T) {
 		smtc.expectedSecret = "valC2"
 	}
 
+	// good case: kv type with property and dot, returns specific value
+	setSecretKVWithKeyDot := func(smtc *secretManagerTestCase) {
+		resources := []sm.SecretResourceIntf{
+			&sm.SecretResource{
+				SecretType: utilpointer.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst),
+				Name:       utilpointer.StringPtr("testyname"),
+				SecretData: secretDataKVComplex,
+			}}
+
+		smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
+		smtc.apiOutput.Resources = resources
+		smtc.ref.Key = secretKV
+		smtc.ref.Property = "special.log"
+		smtc.expectedSecret = "file-content"
+	}
+
+	// good case: kv type without property, returns all
+	setSecretKVWithOutKey := func(smtc *secretManagerTestCase) {
+		resources := []sm.SecretResourceIntf{
+			&sm.SecretResource{
+				SecretType: utilpointer.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst),
+				Name:       utilpointer.StringPtr("testyname"),
+				SecretData: secretDataKVComplex,
+			}}
+
+		smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
+		smtc.apiOutput.Resources = resources
+		smtc.ref.Key = secretKV
+		//smtc.ref.Property = "NO-PROPERTY"
+		smtc.expectedSecret = secretKVComplex
+	}
+
 	successCases := []*secretManagerTestCase{
 		makeValidSecretManagerTestCase(),
 		makeValidSecretManagerTestCaseCustom(setSecretString),
@@ -352,6 +384,8 @@ func TestIBMSecretManagerGetSecret(t *testing.T) {
 		makeValidSecretManagerTestCaseCustom(setSecretKV),
 		makeValidSecretManagerTestCaseCustom(setSecretKVWithKey),
 		makeValidSecretManagerTestCaseCustom(setSecretKVWithKeyPath),
+		makeValidSecretManagerTestCaseCustom(setSecretKVWithKeyDot),
+		makeValidSecretManagerTestCaseCustom(setSecretKVWithOutKey),
 		makeValidSecretManagerTestCaseCustom(badSecretKV),
 		makeValidSecretManagerTestCaseCustom(setSecretPublicCert),
 		makeValidSecretManagerTestCaseCustom(badSecretPublicCert),