Browse Source

Adding docs and implementing ConversionStrategy

Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com>
Gustavo Carvalho 4 years ago
parent
commit
164e8776ec
63 changed files with 276 additions and 106 deletions
  1. 11 0
      apis/externalsecrets/v1alpha1/externalsecret_types.go
  2. 16 2
      apis/externalsecrets/v1beta1/externalsecret_types.go
  3. 20 2
      config/crds/bases/external-secrets.io_externalsecrets.yaml
  4. 20 2
      deploy/crds/bundle.yaml
  5. 82 7
      docs/provider-hashicorp-vault.md
  6. 3 2
      docs/snippets/akeyless-external-secret-json.yaml
  7. 1 1
      docs/snippets/akeyless-external-secret.yaml
  8. 1 1
      docs/snippets/akeyless-secret-store.yaml
  9. 3 2
      docs/snippets/aws-anchore-engine-access-credentials-external-secret.yaml
  10. 1 1
      docs/snippets/aws-jenkins-credential-github-ssh-external-secret.yaml
  11. 1 1
      docs/snippets/aws-jenkins-credential-sonarqube-api-token-external-secret.yaml
  12. 1 1
      docs/snippets/aws-jenkins-credentials-harbor-chart-robot-external-secret.yaml
  13. 1 1
      docs/snippets/aws-parameter-store.yaml
  14. 1 1
      docs/snippets/aws-sm-external-secret.yaml
  15. 1 1
      docs/snippets/aws-sm-store.yaml
  16. 1 1
      docs/snippets/azkv-external-secret.yaml
  17. 1 1
      docs/snippets/azkv-secret-store-mi.yaml
  18. 1 1
      docs/snippets/azkv-secret-store.yaml
  19. 3 2
      docs/snippets/basic-external-secret.yaml
  20. 1 1
      docs/snippets/basic-secret-store.yaml
  21. 1 1
      docs/snippets/controller-class-store.yaml
  22. 3 2
      docs/snippets/fake-provider-es.yaml
  23. 1 1
      docs/snippets/fake-provider-store.yaml
  24. 1 1
      docs/snippets/full-cluster-secret-store.yaml
  25. 13 4
      docs/snippets/full-external-secret.yaml
  26. 1 1
      docs/snippets/full-secret-store.yaml
  27. 3 2
      docs/snippets/gcpsm-data-from-external-secret.yaml
  28. 1 1
      docs/snippets/gcpsm-docker-config-externalsecret.yaml
  29. 1 1
      docs/snippets/gcpsm-external-secret.yaml
  30. 1 1
      docs/snippets/gcpsm-pod-wi-secret-store.yaml
  31. 1 1
      docs/snippets/gcpsm-secret-store.yaml
  32. 1 1
      docs/snippets/gcpsm-ssh-auth-externalsecret.yaml
  33. 1 1
      docs/snippets/gcpsm-tls-externalsecret.yaml
  34. 1 1
      docs/snippets/gcpsm-wi-secret-store.yaml
  35. 3 2
      docs/snippets/gitlab-external-secret-json.yaml
  36. 1 1
      docs/snippets/gitlab-external-secret.yaml
  37. 1 1
      docs/snippets/gitlab-secret-store.yaml
  38. 1 1
      docs/snippets/gitops/crs/clusterSecretStore.yaml
  39. 1 1
      docs/snippets/ibm-es-types.yaml
  40. 1 1
      docs/snippets/ibm-external-secret.yaml
  41. 1 1
      docs/snippets/ibm-secret-store.yaml
  42. 1 1
      docs/snippets/jwk-template-v2-external-secret.yaml
  43. 1 1
      docs/snippets/multiline-template-v1-external-secret.yaml
  44. 1 1
      docs/snippets/multiline-template-v2-external-secret.yaml
  45. 3 2
      docs/snippets/oracle-external-secret.yaml
  46. 2 2
      docs/snippets/oracle-secret-store.yaml
  47. 1 1
      docs/snippets/pkcs12-template-v1-external-secret.yaml
  48. 1 1
      docs/snippets/pkcs12-template-v2-external-secret.yaml
  49. 3 3
      docs/snippets/provider-aws-access.md
  50. 1 1
      docs/snippets/template-v1-from-secret.yaml
  51. 1 1
      docs/snippets/template-v2-from-secret.yaml
  52. 1 1
      docs/snippets/vault-anchore-engine-access-credentials-external-secret.yaml
  53. 1 1
      docs/snippets/vault-approle-store.yaml
  54. 1 1
      docs/snippets/vault-jenkins-credential-github-ssh-access-external-secret.yaml
  55. 1 1
      docs/snippets/vault-jenkins-credential-harbor-chart-robot-external-secret.yaml
  56. 1 1
      docs/snippets/vault-jenkins-credential-sonarqube-api-token-external-secret.yaml
  57. 1 1
      docs/snippets/vault-jwt-store.yaml
  58. 1 1
      docs/snippets/vault-kubernetes-store.yaml
  59. 1 1
      docs/snippets/vault-ldap-store.yaml
  60. 1 1
      docs/snippets/vault-token-store.yaml
  61. 11 1
      pkg/controllers/externalsecret/externalsecret_controller.go
  62. 6 8
      pkg/provider/vault/vault.go
  63. 26 16
      pkg/utils/utils.go

+ 11 - 0
apis/externalsecrets/v1alpha1/externalsecret_types.go

@@ -141,8 +141,19 @@ type ExternalSecretDataRemoteRef struct {
 	// +optional
 	// Used to select a specific property of the Provider value (if a map), if supported
 	Property string `json:"property,omitempty"`
+	// +optional
+	// Used to define a conversion Strategy
+	// +kubebuilder:default="Default"
+	ConversionStrategy ExternalSecretConversionStrategy `json:"conversionStrategy,omitempty"`
 }
 
+type ExternalSecretConversionStrategy string
+
+const (
+	ExternalSecretConversionDefault ExternalSecretConversionStrategy = "Default"
+	ExternalSecretConversionUnicode ExternalSecretConversionStrategy = "Unicode"
+)
+
 // ExternalSecretSpec defines the desired state of ExternalSecret.
 type ExternalSecretSpec struct {
 	SecretStoreRef SecretStoreRef `json:"secretStoreRef"`

+ 16 - 2
apis/externalsecrets/v1beta1/externalsecret_types.go

@@ -159,8 +159,20 @@ type ExternalSecretDataRemoteRef struct {
 	// +optional
 	// Used to select a specific property of the Provider value (if a map), if supported
 	Property string `json:"property,omitempty"`
+
+	// +optional
+	// Used to define a conversion Strategy
+	// +kubebuilder:default="Default"
+	ConversionStrategy ExternalSecretConversionStrategy `json:"conversionStrategy,omitempty"`
 }
 
+type ExternalSecretConversionStrategy string
+
+const (
+	ExternalSecretConversionDefault ExternalSecretConversionStrategy = "Default"
+	ExternalSecretConversionUnicode ExternalSecretConversionStrategy = "Unicode"
+)
+
 // +kubebuilder:validation:MinProperties=1
 // +kubebuilder:validation:MaxProperties=1
 type ExternalSecretDataFromRemoteRef struct {
@@ -172,8 +184,6 @@ type ExternalSecretDataFromRemoteRef struct {
 	Find *ExternalSecretFind `json:"find,omitempty"`
 }
 
-// +kubebuilder:validation:MinProperties=1
-// +kubebuilder:validation:MaxProperties=1
 type ExternalSecretFind struct {
 	// A root path to start the find operations.
 	// +optional
@@ -185,6 +195,10 @@ type ExternalSecretFind struct {
 	// Find secrets based on tags.
 	// +optional
 	Tags map[string]string `json:"tags,omitempty"`
+	// +optional
+	// Used to define a conversion Strategy
+	// +kubebuilder:default="Default"
+	ConversionStrategy ExternalSecretConversionStrategy `json:"conversionStrategy,omitempty"`
 }
 
 type FindName struct {

+ 20 - 2
config/crds/bases/external-secrets.io_externalsecrets.yaml

@@ -59,6 +59,10 @@ spec:
                       description: ExternalSecretDataRemoteRef defines Provider data
                         location.
                       properties:
+                        conversionStrategy:
+                          default: Default
+                          description: Used to define a conversion Strategy
+                          type: string
                         key:
                           description: Key is the key used in the Provider, mandatory
                           type: string
@@ -87,6 +91,10 @@ spec:
                 items:
                   description: ExternalSecretDataRemoteRef defines Provider data location.
                   properties:
+                    conversionStrategy:
+                      default: Default
+                      description: Used to define a conversion Strategy
+                      type: string
                     key:
                       description: Key is the key used in the Provider, mandatory
                       type: string
@@ -294,6 +302,10 @@ spec:
                       description: ExternalSecretDataRemoteRef defines Provider data
                         location.
                       properties:
+                        conversionStrategy:
+                          default: Default
+                          description: Used to define a conversion Strategy
+                          type: string
                         key:
                           description: Key is the key used in the Provider, mandatory
                           type: string
@@ -327,6 +339,10 @@ spec:
                       description: Used to extract multiple key/value pairs from one
                         secret
                       properties:
+                        conversionStrategy:
+                          default: Default
+                          description: Used to define a conversion Strategy
+                          type: string
                         key:
                           description: Key is the key used in the Provider, mandatory
                           type: string
@@ -343,9 +359,11 @@ spec:
                       type: object
                     find:
                       description: Used to find secrets based on tags or regular expressions
-                      maxProperties: 1
-                      minProperties: 1
                       properties:
+                        conversionStrategy:
+                          default: Default
+                          description: Used to define a conversion Strategy
+                          type: string
                         name:
                           description: Finds secrets based on the name.
                           properties:

+ 20 - 2
deploy/crds/bundle.yaml

@@ -2019,6 +2019,10 @@ spec:
                       remoteRef:
                         description: ExternalSecretDataRemoteRef defines Provider data location.
                         properties:
+                          conversionStrategy:
+                            default: Default
+                            description: Used to define a conversion Strategy
+                            type: string
                           key:
                             description: Key is the key used in the Provider, mandatory
                             type: string
@@ -2043,6 +2047,10 @@ spec:
                   items:
                     description: ExternalSecretDataRemoteRef defines Provider data location.
                     properties:
+                      conversionStrategy:
+                        default: Default
+                        description: Used to define a conversion Strategy
+                        type: string
                       key:
                         description: Key is the key used in the Provider, mandatory
                         type: string
@@ -2226,6 +2234,10 @@ spec:
                       remoteRef:
                         description: ExternalSecretDataRemoteRef defines Provider data location.
                         properties:
+                          conversionStrategy:
+                            default: Default
+                            description: Used to define a conversion Strategy
+                            type: string
                           key:
                             description: Key is the key used in the Provider, mandatory
                             type: string
@@ -2254,6 +2266,10 @@ spec:
                       extract:
                         description: Used to extract multiple key/value pairs from one secret
                         properties:
+                          conversionStrategy:
+                            default: Default
+                            description: Used to define a conversion Strategy
+                            type: string
                           key:
                             description: Key is the key used in the Provider, mandatory
                             type: string
@@ -2268,9 +2284,11 @@ spec:
                         type: object
                       find:
                         description: Used to find secrets based on tags or regular expressions
-                        maxProperties: 1
-                        minProperties: 1
                         properties:
+                          conversionStrategy:
+                            default: Default
+                            description: Used to define a conversion Strategy
+                            type: string
                           name:
                             description: Finds secrets based on the name.
                             properties:

+ 82 - 7
docs/provider-hashicorp-vault.md

@@ -11,7 +11,7 @@ management. Vault itself implements lots of different secret engines, as of now
 First, create a SecretStore with a vault backend. For the sake of simplicity we'll use a static token `root`:
 
 ```yaml
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: vault-backend
@@ -46,7 +46,7 @@ vault kv put secret/foo my-value=s3cr3t
 Now create a ExternalSecret that uses the above SecretStore:
 
 ```yaml
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: vault-example
@@ -76,7 +76,7 @@ data:
 You can fetch all key/value pairs for a given path If you leave the `remoteRef.property` empty. This returns the json-encoded secret value for that path.
 
 ```yaml
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: vault-example
@@ -105,7 +105,7 @@ Given the following secret - assume its path is `/dev/config`:
 
 You can set the `remoteRef.property` to point to the nested key using a [gjson](https://github.com/tidwall/gjson) expression.
 ```yaml
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: vault-example
@@ -141,15 +141,16 @@ Given the following secret - assume its path is `/dev/config`:
 
 You can set the `remoteRef.property` to point to the nested key using a [gjson](https://github.com/tidwall/gjson) expression.
 ```yaml
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: vault-example
 spec:
   # ...
   dataFrom:
-  - key: /dev/config
-    property: foo.nested
+  - extract:
+      key: /dev/config
+      property: foo.nested
 ```
 
 That results in a secret with these values:
@@ -158,6 +159,80 @@ bar=mysecret
 baz=bang
 ```
 
+#### Getting multiple secrets
+
+You can extract multiple secrets from Hashicorp vault by using `dataFrom.Find`
+
+Currently, `dataFrom.Find` allows users to fetch secret names that match a given regexp pattern, or fetch secrets whose `custom_metadata` tags match a predefined set.
+
+Given the following secret - assume its path is `/dev/config`:
+```json
+{
+  "foo": {
+    "nested": {
+      "bar": "mysecret",
+      "baz": "bang"
+    }
+  }
+}
+```
+
+Also consider the following secret has the following `custom_metadata`:
+```json
+{
+  "environment": "dev",
+  "component": "app-1"
+}
+```
+
+It is possible to find this secret by all the following possibilities:
+```yaml
+apiVersion: external-secrets.io/v1beta1
+kind: ExternalSecret
+metadata:
+  name: vault-example
+spec:
+  # ...
+  dataFrom: 
+  - find: #will return every secret with 'dev' in it (including paths) 
+      name: 
+        regexp: dev
+  - find: #will return every secret matching environment:dev tags from dev/ folder and beyond 
+      tags: 
+        environment: dev
+```
+will generate a secret with: 
+```json
+{
+  "dev_config":"{\"foo\": {\"nested\": {\"bar\": \"mysecret\",\"baz\": \"bang\"}}}"
+}
+```
+
+Currently, `Find` operations are recursive throughout a given vault folder, starting on `provider.Path` definition. It is recommended to narrow down the scope of search by setting a `find.path` variable. This is also useful to automatically reduce the resulting secret key names:
+```yaml
+apiVersion: external-secrets.io/v1beta1
+kind: ExternalSecret
+metadata:
+  name: vault-example
+spec:
+  # ...
+  dataFrom: 
+  - find: #will return every secret from dev/ folder 
+      path: dev
+      name: 
+        regexp: ".*"
+  - find: #will return every secret matching environment:dev tags from dev/ folder
+      path: dev
+      tags: 
+        environment: dev
+```
+Will generate a secret with:
+```json
+{
+  "config":"{\"foo\": {\"nested\": {\"bar\": \"mysecret\",\"baz\": \"bang\"}}}"
+}
+
+```
 ### Authentication
 
 We support five different modes for authentication:

+ 3 - 2
docs/snippets/akeyless-external-secret-json.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: akeyless-external-secret-example-json
@@ -15,4 +15,5 @@ spec:
 
   # for json formatted secrets: each key in the json will be used as the secret key in the SECRET k8s target object
   dataFrom:
-  - key: secret-name # Full path of the secret on Akeyless
+  - extract:
+      key: secret-name # Full path of the secret on Akeyless

+ 1 - 1
docs/snippets/akeyless-external-secret.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: akeyless-external-secret-example

+ 1 - 1
docs/snippets/akeyless-secret-store.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: akeyless-secret-store

+ 3 - 2
docs/snippets/aws-anchore-engine-access-credentials-external-secret.yaml

@@ -1,5 +1,5 @@
 ---
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: anchore-access-credentials
@@ -12,4 +12,5 @@ spec:
   target:
     name: anchore-access-credentials
   dataFrom:
-  - key: service/anchore-engine/engineAccess
+  - extract:
+      key: service/anchore-engine/engineAccess

+ 1 - 1
docs/snippets/aws-jenkins-credential-github-ssh-external-secret.yaml

@@ -1,5 +1,5 @@
 ---
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: github-ssh-access

+ 1 - 1
docs/snippets/aws-jenkins-credential-sonarqube-api-token-external-secret.yaml

@@ -1,5 +1,5 @@
 ---
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: sonarqube-api-token

+ 1 - 1
docs/snippets/aws-jenkins-credentials-harbor-chart-robot-external-secret.yaml

@@ -1,5 +1,5 @@
 ---
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: harbor-chart-robot

+ 1 - 1
docs/snippets/aws-parameter-store.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: secretstore-sample

+ 1 - 1
docs/snippets/aws-sm-external-secret.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: example

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

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: secretstore-sample

+ 1 - 1
docs/snippets/azkv-external-secret.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: example-external-secret

+ 1 - 1
docs/snippets/azkv-secret-store-mi.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: example-secret-store

+ 1 - 1
docs/snippets/azkv-secret-store.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: example-secret-store

+ 3 - 2
docs/snippets/basic-external-secret.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: example
@@ -17,4 +17,5 @@ spec:
       version: provider-key-version
       property: provider-key-property
   dataFrom:
-  - key: remote-key-in-the-provider
+  - extract:
+      key: remote-key-in-the-provider

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

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: secretstore-sample

+ 1 - 1
docs/snippets/controller-class-store.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: controller-custom-example

+ 3 - 2
docs/snippets/fake-provider-es.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: example
@@ -15,4 +15,5 @@ spec:
       key: /foo/bar
       version: v1
   dataFrom:
-  - key: /foo/baz
+  - extract:
+      key: /foo/baz

+ 1 - 1
docs/snippets/fake-provider-store.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ClusterSecretStore
 metadata:
   name: fake

+ 1 - 1
docs/snippets/full-cluster-secret-store.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ClusterSecretStore
 metadata:
   name: example

+ 13 - 4
docs/snippets/full-external-secret.yaml

@@ -1,5 +1,5 @@
 {% raw %}
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: "hello-world"
@@ -73,9 +73,18 @@ spec:
   # Used to fetch all properties from the Provider key
   # If multiple dataFrom are specified, secrets are merged in the specified order
   dataFrom:
-  - key: provider-key
-    version: provider-key-version
-    property: provider-key-property
+  - extract:
+      key: provider-key
+      version: provider-key-version
+      property: provider-key-property
+      conversionStrategy: Default
+  - find:
+      path: path-to-filter 
+      name: 
+        regexp: ".*foobar.*"
+      tags: 
+        foo: bar
+      conversionStrategy: Unicode
 
 status:
   # refreshTime is the time and date the external secret was fetched and

+ 1 - 1
docs/snippets/full-secret-store.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: example

+ 3 - 2
docs/snippets/gcpsm-data-from-external-secret.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: example
@@ -11,4 +11,5 @@ spec:
     name: secret-to-be-created  # name of the k8s Secret to be created
     creationPolicy: Owner
   dataFrom:
-  - key: all-keys-example-secret  # name of the GCPSM secret
+  - extract:
+      key: all-keys-example-secret  # name of the GCPSM secret

+ 1 - 1
docs/snippets/gcpsm-docker-config-externalsecret.yaml

@@ -1,5 +1,5 @@
 {% raw %}
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: dk-cfg-example

+ 1 - 1
docs/snippets/gcpsm-external-secret.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: example

+ 1 - 1
docs/snippets/gcpsm-pod-wi-secret-store.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: example

+ 1 - 1
docs/snippets/gcpsm-secret-store.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: example

+ 1 - 1
docs/snippets/gcpsm-ssh-auth-externalsecret.yaml

@@ -1,5 +1,5 @@
 {% raw %}
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: ssh-auth-example

+ 1 - 1
docs/snippets/gcpsm-tls-externalsecret.yaml

@@ -1,5 +1,5 @@
 {% raw %}
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: template-tls-example

+ 1 - 1
docs/snippets/gcpsm-wi-secret-store.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ClusterSecretStore
 metadata:
   name: example

+ 3 - 2
docs/snippets/gitlab-external-secret-json.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: gitlab-external-secret-example
@@ -15,4 +15,5 @@ spec:
 
   # each secret name in the KV will be used as the secret key in the SECRET k8s target object
   dataFrom:
-  - key: "myJsonVariable" # Key of the variable on Gitlab
+  - extract:
+      key: "myJsonVariable" # Key of the variable on Gitlab

+ 1 - 1
docs/snippets/gitlab-external-secret.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: gitlab-external-secret-example

+ 1 - 1
docs/snippets/gitlab-secret-store.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: gitlab-secret-store

+ 1 - 1
docs/snippets/gitops/crs/clusterSecretStore.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ClusterSecretStore
 metadata:
   name: vault-backend-global

+ 1 - 1
docs/snippets/ibm-es-types.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: ibm-sample

+ 1 - 1
docs/snippets/ibm-external-secret.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: external-secret-sample

+ 1 - 1
docs/snippets/ibm-secret-store.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: secretstore-sample

+ 1 - 1
docs/snippets/jwk-template-v2-external-secret.yaml

@@ -1,5 +1,5 @@
 {% raw %}
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: template

+ 1 - 1
docs/snippets/multiline-template-v1-external-secret.yaml

@@ -1,5 +1,5 @@
 {% raw %}
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: template

+ 1 - 1
docs/snippets/multiline-template-v2-external-secret.yaml

@@ -1,5 +1,5 @@
 {% raw %}
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: template

+ 3 - 2
docs/snippets/oracle-external-secret.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: example
@@ -11,4 +11,5 @@ spec:
     name: secret-to-be-created # Name for the secret on the cluster
     creationPolicy: Owner
   dataFrom:
-    - key: the-secret-name
+  - extract:
+      key: the-secret-name

+ 2 - 2
docs/snippets/oracle-secret-store.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: example-instance-principal
@@ -10,7 +10,7 @@ spec:
 
 ---
 
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: example-auth

+ 1 - 1
docs/snippets/pkcs12-template-v1-external-secret.yaml

@@ -1,5 +1,5 @@
 {% raw %}
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: template

+ 1 - 1
docs/snippets/pkcs12-template-v2-external-secret.yaml

@@ -1,5 +1,5 @@
 {% raw %}
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: template

+ 3 - 3
docs/snippets/provider-aws-access.md

@@ -13,7 +13,7 @@ You can attach a role to the pod using [IRSA](https://docs.aws.amazon.com/eks/la
 Based on the Pod's identity you can do a `sts:assumeRole` before fetching the secrets to limit access to certain keys in your provider. This is optional.
 
 ```yaml
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: team-b-store
@@ -33,7 +33,7 @@ spec:
 You can store Access Key ID & Secret Access Key in a `Kind=Secret` and reference it from a SecretStore.
 
 ```yaml
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: team-b-store
@@ -78,7 +78,7 @@ metadata:
 Reference the service account from above in the Secret Store:
 
 ```yaml
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: secretstore-sample

+ 1 - 1
docs/snippets/template-v1-from-secret.yaml

@@ -14,7 +14,7 @@ data:
         password: "{{ .password | toString }}" # <-- convert []byte to string
         user: "{{ .user | toString }}"         # <-- convert []byte to string
 ---
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: my-template-example

+ 1 - 1
docs/snippets/template-v2-from-secret.yaml

@@ -14,7 +14,7 @@ data:
         password: "{{ .password }}"
         user: "{{ .user }}"
 ---
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: my-template-example

+ 1 - 1
docs/snippets/vault-anchore-engine-access-credentials-external-secret.yaml

@@ -1,5 +1,5 @@
 {% raw %}
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: anchore-access-credentials

+ 1 - 1
docs/snippets/vault-approle-store.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: vault-backend

+ 1 - 1
docs/snippets/vault-jenkins-credential-github-ssh-access-external-secret.yaml

@@ -1,5 +1,5 @@
 {% raw %}
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: github-ssh-access

+ 1 - 1
docs/snippets/vault-jenkins-credential-harbor-chart-robot-external-secret.yaml

@@ -1,5 +1,5 @@
 {% raw %}
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: harbor-chart-robot

+ 1 - 1
docs/snippets/vault-jenkins-credential-sonarqube-api-token-external-secret.yaml

@@ -1,5 +1,5 @@
 {% raw %}
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: ExternalSecret
 metadata:
   name: sonarqube-api-token

+ 1 - 1
docs/snippets/vault-jwt-store.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: vault-backend

+ 1 - 1
docs/snippets/vault-kubernetes-store.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: vault-backend

+ 1 - 1
docs/snippets/vault-ldap-store.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: vault-backend

+ 1 - 1
docs/snippets/vault-token-store.yaml

@@ -1,4 +1,4 @@
-apiVersion: external-secrets.io/v1alpha1
+apiVersion: external-secrets.io/v1beta1
 kind: SecretStore
 metadata:
   name: vault-backend

+ 11 - 1
pkg/controllers/externalsecret/externalsecret_controller.go

@@ -46,6 +46,8 @@ const (
 	requeueAfter = time.Second * 30
 
 	errGetES                 = "could not get ExternalSecret"
+	errConvert               = "could not apply conversion strategy to keys: %v"
+	errFindSecretKey         = "could not find secret %v: %v"
 	errUpdateSecret          = "could not update Secret"
 	errPatchStatus           = "unable to patch status"
 	errGetSecretStore        = "could not get SecretStore %q, %w"
@@ -400,13 +402,21 @@ func (r *Reconciler) getProviderSecretData(ctx context.Context, providerClient e
 		if remoteRef.Find != nil {
 			secretMap, err = providerClient.GetAllSecrets(ctx, *remoteRef.Find)
 			if err != nil {
-				return nil, fmt.Errorf(errGetSecretKey, remoteRef.Extract.Key, externalSecret.Name, err)
+				return nil, fmt.Errorf(errFindSecretKey, externalSecret.Name, err)
+			}
+			secretMap, err = utils.ConvertKeys(remoteRef.Find.ConversionStrategy, secretMap)
+			if err != nil {
+				return nil, fmt.Errorf(errConvert, err)
 			}
 		} else if remoteRef.Extract != nil {
 			secretMap, err = providerClient.GetSecretMap(ctx, *remoteRef.Extract)
 			if err != nil {
 				return nil, fmt.Errorf(errGetSecretKey, remoteRef.Extract.Key, externalSecret.Name, err)
 			}
+			secretMap, err = utils.ConvertKeys(remoteRef.Extract.ConversionStrategy, secretMap)
+			if err != nil {
+				return nil, fmt.Errorf(errConvert, err)
+			}
 		}
 
 		providerData = utils.MergeByteMap(providerData, secretMap)

+ 6 - 8
pkg/provider/vault/vault.go

@@ -276,11 +276,10 @@ func (v *client) findSecretsFromTags(ctx context.Context, candidates []string, t
 			if removeFromName != "" {
 				name = strings.TrimPrefix(name, removeFromName)
 			}
-			newName := utils.ConvertName(name)
-			if _, exists := secrets[newName]; exists {
-				return nil, fmt.Errorf(errDuplicateSecret, newName)
+			if _, exists := secrets[name]; exists {
+				return nil, fmt.Errorf(errDuplicateSecret, name)
 			}
-			secrets[newName] = secret
+			secrets[name] = secret
 		}
 	}
 	return secrets, nil
@@ -301,11 +300,10 @@ func (v *client) findSecretsFromName(ctx context.Context, candidates []string, r
 			if removeFromName != "" {
 				name = strings.TrimPrefix(name, removeFromName)
 			}
-			newName := utils.ConvertName(name)
-			if _, exists := secrets[newName]; exists {
-				return nil, fmt.Errorf(errDuplicateSecret, newName)
+			if _, exists := secrets[name]; exists {
+				return nil, fmt.Errorf(errDuplicateSecret, name)
 			}
-			secrets[newName] = secret
+			secrets[name] = secret
 		}
 	}
 	return secrets, nil

+ 26 - 16
pkg/utils/utils.go

@@ -21,7 +21,6 @@ import (
 	"fmt"
 	"reflect"
 	"strings"
-
 	"unicode"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
@@ -36,23 +35,34 @@ func MergeByteMap(dst, src map[string][]byte) map[string][]byte {
 	return dst
 }
 
-// ConvertName converts a string into a secret-key compatible string.
-// Replaces any non-alphanumeric characters with its unicode code.
-func ConvertName(in string) string {
-	out := make([]string, len(in))
-	rs := []rune(in)
-	for k, r := range rs {
-		if !unicode.IsNumber(r) &&
-			!unicode.IsLetter(r) &&
-			r != '-' &&
-			r != '.' &&
-			r != '_' {
-			out[k] = fmt.Sprintf("_U%04x_", r)
-		} else {
-			out[k] = string(r)
+// ConvertKeys converts a secret map into a valid key.
+// Replaces any non-alphanumeric characters depending on convert strategy.
+func ConvertKeys(strategy esv1beta1.ExternalSecretConversionStrategy, in map[string][]byte) (map[string][]byte, error) {
+	out := make(map[string][]byte)
+	for k, v := range in {
+		rs := []rune(k)
+		newName := make([]string, len(rs))
+		for rk, rv := range rs {
+			if !unicode.IsNumber(rv) &&
+				!unicode.IsLetter(rv) &&
+				rv != '-' &&
+				rv != '.' &&
+				rv != '_' {
+				switch strategy {
+				case esv1beta1.ExternalSecretConversionDefault:
+					newName[rk] = "_"
+				case esv1beta1.ExternalSecretConversionUnicode:
+					newName[rk] = fmt.Sprintf("_U%04x_", rv)
+				default:
+					return nil, fmt.Errorf("unknown conversion strategy: %s", strategy)
+				}
+			} else {
+				newName[rk] = string(rv)
+			}
 		}
+		out[strings.Join(newName, "")] = v
 	}
-	return strings.Join(out, "")
+	return out, nil
 }
 
 // MergeStringMap performs a deep clone from src to dest.