Browse Source

ref: simplify and document transform rewrite method (#5450)

* simplify rewrite transform implementation

Signed-off-by: Riccardo M. Cefala <riccardo.cefala@gmail.com>

* introduce documentation for rewrite transform

Signed-off-by: Riccardo M. Cefala <riccardo.cefala@gmail.com>

* add rewrite transform example in documentation

Signed-off-by: Riccardo M. Cefala <riccardo.cefala@gmail.com>

---------

Signed-off-by: Riccardo M. Cefala <riccardo.cefala@gmail.com>
Co-authored-by: Gergely Brautigam <skarlso777@gmail.com>
Riccardo M. Cefala 6 months ago
parent
commit
fcb2564a2f
3 changed files with 64 additions and 36 deletions
  1. 35 0
      docs/guides/datafrom-rewrite.md
  2. 17 0
      docs/snippets/datafrom-rewrite-transform.yaml
  3. 12 36
      pkg/esutils/utils.go

+ 35 - 0
docs/guides/datafrom-rewrite.md

@@ -11,6 +11,11 @@ Rewrite operations are all applied before `ConversionStrategy` is applied.
 ### Regexp
 This method implements rewriting through the use of regular expressions. It needs a `source` and a `target` field. The source field is where the definition of the matching regular expression goes, where the `target` field is where the replacing expression goes.
 
+### Transform
+This method uses Go templating to rewrite the keys of each secret. The `template` field is used to specify the template. You can reference the key of each secret by the `.value` string.
+
+You can also use [helper functions](templating.md#helper-functions) in the template.
+
 ### Merge
 This method implements rewriting keys by merging operation and solving key collisions. It supports two merging strategies: `Extract` and `JSON`.
 
@@ -140,6 +145,36 @@ data:
     PASSWORD:  WVlZWQ== #YYYY
 ```
 
+### Transform secret keys
+
+The following ExternalSecret:
+
+```yaml
+{% include 'datafrom-rewrite-transform.yaml' %}
+```
+
+Uses a template to transform all secret keys into an "environment variable" format by capitalizing, replacing `-` with `_` and prefixing them with `ENV_`.
+
+In this example, if we had the following secrets available in the provider:
+```json
+{
+"foo-nut-bar": "HELLO1"
+"foo-naz-bar": "HELLO2"
+"foo-bar-baz": '{"john": "doe"}'
+}
+```
+
+the output kubernetes secret would be:
+```yaml
+apiVersion: v1
+kind: Secret
+type: Opaque
+data:
+  ENV_FOO_BAR_BAZ: eyJqb2huIjogImRvZSJ9
+  ENV_FOO_NAZ_BAR: SEVMTE8y
+  ENV_FOO_NUT_BAR: SEVMTE8x
+```
+
 ## Limitations
 
 Regexp Rewrite is based on golang `regexp`, which in turns implements `RE2` regexp language. There a a series of known limitations to this implementation, such as:

+ 17 - 0
docs/snippets/datafrom-rewrite-transform.yaml

@@ -0,0 +1,17 @@
+{% raw %}
+apiVersion: external-secrets.io/v1
+kind: ExternalSecret
+metadata:
+  name: external-secret-transform
+spec:
+  secretStoreRef:
+    name: fake
+    kind: ClusterSecretStore
+  dataFrom:
+    - find:
+        name:
+          regexp: ".*"
+      rewrite:
+      - transform:
+          template: 'ENV_{{ .value | upper | replace "-" "_" }}'
+{% endraw %}

+ 12 - 36
pkg/esutils/utils.go

@@ -36,7 +36,7 @@ import (
 	"sort"
 	"strconv"
 	"strings"
-	tpl "text/template"
+	template "text/template"
 	"time"
 	"unicode"
 
@@ -56,12 +56,7 @@ import (
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
 	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
 	"github.com/external-secrets/external-secrets/pkg/esutils/resolvers"
-	"github.com/external-secrets/external-secrets/pkg/template/v2"
-)
-
-const (
-	errParse   = "unable to parse transform template: %s"
-	errExecute = "unable to execute transform template: %s"
+	estemplate "github.com/external-secrets/external-secrets/pkg/template/v2"
 )
 
 var (
@@ -218,40 +213,21 @@ func RewriteRegexp(operation esv1.ExternalSecretRewriteRegexp, in map[string][]b
 // RewriteTransform applies string transformation on each secret key name to rewrite.
 func RewriteTransform(operation esv1.ExternalSecretRewriteTransform, in map[string][]byte) (map[string][]byte, error) {
 	out := make(map[string][]byte)
-	for key, value := range in {
-		data := map[string][]byte{
-			"value": []byte(key),
-		}
 
-		result, err := transform(operation.Template, data)
-		if err != nil {
-			return nil, fmt.Errorf("transform failed with failed to transform key: %w", err)
-		}
-
-		newKey := string(result)
-		out[newKey] = value
+	tmpl, err := template.New("transform").Funcs(estemplate.FuncMap()).Parse(operation.Template)
+	if err != nil {
+		return nil, fmt.Errorf("transform failed with failed to parse template: %w", err)
 	}
-	return out, nil
-}
 
-func transform(val string, data map[string][]byte) ([]byte, error) {
-	strValData := make(map[string]string, len(data))
-	for k := range data {
-		strValData[k] = string(data[k])
+	for key, value := range in {
+		var buf bytes.Buffer
+		if err := tmpl.Execute(&buf, map[string]string{"value": key}); err != nil {
+			return nil, fmt.Errorf("transform failed with failed to execute template for key %q: %w", key, err)
+		}
+		out[buf.String()] = value
 	}
 
-	t, err := tpl.New("transform").
-		Funcs(template.FuncMap()).
-		Parse(val)
-	if err != nil {
-		return nil, fmt.Errorf(errParse, err)
-	}
-	buf := bytes.NewBuffer(nil)
-	err = t.Execute(buf, strValData)
-	if err != nil {
-		return nil, fmt.Errorf(errExecute, err)
-	}
-	return buf.Bytes(), nil
+	return out, nil
 }
 
 // DecodeMap decodes values from a secretMap.