mirror of
https://github.com/external-secrets/external-secrets.git
synced 2024-12-14 11:57:59 +00:00
feat: implement template engine v2
Signed-off-by: Moritz Johner <beller.moritz@googlemail.com>
This commit is contained in:
parent
9fa3a965bc
commit
54e68399ec
16 changed files with 863 additions and 13 deletions
|
@ -59,6 +59,12 @@ type ExternalSecretTemplate struct {
|
|||
// +optional
|
||||
Type corev1.SecretType `json:"type,omitempty"`
|
||||
|
||||
// EngineVersion specifies the template engine version
|
||||
// that should be used to compile/execute the
|
||||
// template specified in .data and .templateFrom[].
|
||||
// +kubebuilder:default="v1"
|
||||
EngineVersion TemplateEngineVersion `json:"engineVersion,omitempty"`
|
||||
|
||||
// +optional
|
||||
Metadata ExternalSecretTemplateMetadata `json:"metadata,omitempty"`
|
||||
|
||||
|
@ -69,6 +75,13 @@ type ExternalSecretTemplate struct {
|
|||
TemplateFrom []TemplateFrom `json:"templateFrom,omitempty"`
|
||||
}
|
||||
|
||||
type TemplateEngineVersion string
|
||||
|
||||
const (
|
||||
TemplateEngineV1 TemplateEngineVersion = "v1"
|
||||
TemplateEngineV2 TemplateEngineVersion = "v2"
|
||||
)
|
||||
|
||||
// +kubebuilder:validation:MinProperties=1
|
||||
// +kubebuilder:validation:MaxProperties=1
|
||||
type TemplateFrom struct {
|
||||
|
|
|
@ -148,6 +148,12 @@ spec:
|
|||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
engineVersion:
|
||||
default: v1
|
||||
description: EngineVersion specifies the template engine version
|
||||
that should be used to compile/execute the template specified
|
||||
in .data and .templateFrom[].
|
||||
type: string
|
||||
metadata:
|
||||
description: ExternalSecretTemplateMetadata defines metadata
|
||||
fields for the Secret blueprint.
|
||||
|
|
|
@ -110,8 +110,9 @@ func (f *Framework) Install(a addon.Addon) {
|
|||
|
||||
// Compose helps define multiple testcases with same/different auth methods.
|
||||
func Compose(descAppend string, f *Framework, fn func(f *Framework) (string, func(*TestCase)), tweaks ...func(*TestCase)) TableEntry {
|
||||
desc, tfn := fn(f)
|
||||
tweaks = append(tweaks, tfn)
|
||||
// prepend common fn to tweaks
|
||||
desc, cfn := fn(f)
|
||||
tweaks = append([]func(*TestCase){cfn}, tweaks...)
|
||||
|
||||
// need to convert []func to []interface{}
|
||||
ifs := make([]interface{}, len(tweaks))
|
||||
|
|
|
@ -20,5 +20,6 @@ import (
|
|||
_ "github.com/external-secrets/external-secrets/e2e/suite/aws/secretsmanager"
|
||||
_ "github.com/external-secrets/external-secrets/e2e/suite/azure"
|
||||
_ "github.com/external-secrets/external-secrets/e2e/suite/gcp"
|
||||
_ "github.com/external-secrets/external-secrets/e2e/suite/template"
|
||||
_ "github.com/external-secrets/external-secrets/e2e/suite/vault"
|
||||
)
|
||||
|
|
89
e2e/suite/template/provider.go
Normal file
89
e2e/suite/template/provider.go
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
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 template
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
// nolint
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
|
||||
// nolint
|
||||
. "github.com/onsi/gomega"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
|
||||
"github.com/external-secrets/external-secrets/e2e/framework"
|
||||
)
|
||||
|
||||
type templateProvider struct {
|
||||
framework *framework.Framework
|
||||
}
|
||||
|
||||
func newProvider(f *framework.Framework) *templateProvider {
|
||||
prov := &templateProvider{
|
||||
framework: f,
|
||||
}
|
||||
BeforeEach(prov.BeforeEach)
|
||||
return prov
|
||||
}
|
||||
|
||||
func (s *templateProvider) CreateSecret(key, val string) {
|
||||
// noop: this provider implements static key/value pairs
|
||||
}
|
||||
|
||||
func (s *templateProvider) DeleteSecret(key string) {
|
||||
// noop: this provider implements static key/value pairs
|
||||
}
|
||||
|
||||
func (s *templateProvider) BeforeEach() {
|
||||
// Create a secret store - change these values to match YAML
|
||||
By("creating a secret store for credentials")
|
||||
secretStore := &esv1alpha1.SecretStore{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: s.framework.Namespace.Name,
|
||||
Namespace: s.framework.Namespace.Name,
|
||||
},
|
||||
Spec: esv1alpha1.SecretStoreSpec{
|
||||
Provider: &esv1alpha1.SecretStoreProvider{
|
||||
Fake: &esv1alpha1.FakeProvider{
|
||||
Data: []esv1alpha1.FakeProviderData{
|
||||
{
|
||||
Key: "foo",
|
||||
Value: "bar",
|
||||
},
|
||||
{
|
||||
Key: "baz",
|
||||
Value: "bang",
|
||||
},
|
||||
{
|
||||
Key: "map",
|
||||
ValueMap: map[string]string{
|
||||
"foo": "barmap",
|
||||
"bar": "bangmap",
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "json",
|
||||
Value: `{"foo":{"bar":"baz"}}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := s.framework.CRClient.Create(context.Background(), secretStore)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
101
e2e/suite/template/template.go
Normal file
101
e2e/suite/template/template.go
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
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.
|
||||
limitations under the License.
|
||||
*/
|
||||
package template
|
||||
|
||||
import (
|
||||
|
||||
// nolint
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
||||
esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
|
||||
"github.com/external-secrets/external-secrets/e2e/framework"
|
||||
)
|
||||
|
||||
var _ = Describe("[template]", Label("template"), func() {
|
||||
f := framework.New("eso-template")
|
||||
prov := newProvider(f)
|
||||
|
||||
DescribeTable("sync secrets", framework.TableFunc(f, prov),
|
||||
framework.Compose("template v1", f, genericTemplate, useTemplateV1),
|
||||
framework.Compose("template v2", f, genericTemplate, useTemplateV2),
|
||||
)
|
||||
})
|
||||
|
||||
// useTemplateV1 specifies a test case which uses the template engine v1.
|
||||
func useTemplateV1(tc *framework.TestCase) {
|
||||
tc.ExternalSecret.Spec.Target.Template = &esv1alpha1.ExternalSecretTemplate{
|
||||
EngineVersion: esv1alpha1.TemplateEngineV1,
|
||||
Data: map[string]string{
|
||||
"my-data": "executed: {{ .singlefoo | toString }}|{{ .singlebaz | toString }}",
|
||||
"other": `{{ .foo | toString }}|{{ .bar | toString }}`,
|
||||
},
|
||||
}
|
||||
tc.ExpectedSecret.Data = map[string][]byte{
|
||||
"my-data": []byte(`executed: bar|bang`),
|
||||
"other": []byte(`barmap|bangmap`),
|
||||
}
|
||||
}
|
||||
|
||||
// useTemplateV2 specifies a test case which uses the template engine v2.
|
||||
func useTemplateV2(tc *framework.TestCase) {
|
||||
tc.ExternalSecret.Spec.Target.Template = &esv1alpha1.ExternalSecretTemplate{
|
||||
EngineVersion: esv1alpha1.TemplateEngineV2,
|
||||
Data: map[string]string{
|
||||
"my-data": "executed: {{ .singlefoo }}|{{ .singlebaz }}",
|
||||
"other": `{{ .foo }}|{{ .bar }}`,
|
||||
"sprig-str": `{{ .foo | upper }}`,
|
||||
"json-ex": `{{ $var := .singlejson | fromJson }}{{ $var.foo | toJson }}`,
|
||||
},
|
||||
}
|
||||
tc.ExpectedSecret.Data = map[string][]byte{
|
||||
"my-data": []byte(`executed: bar|bang`),
|
||||
"other": []byte(`barmap|bangmap`),
|
||||
"sprig-str": []byte(`BARMAP`),
|
||||
"json-ex": []byte(`{"bar":"baz"}`),
|
||||
}
|
||||
}
|
||||
|
||||
// This case uses template engine v1.
|
||||
func genericTemplate(f *framework.Framework) (string, func(*framework.TestCase)) {
|
||||
return "[template] should execute template v1", func(tc *framework.TestCase) {
|
||||
tc.ExpectedSecret = &v1.Secret{
|
||||
Type: v1.SecretTypeOpaque,
|
||||
}
|
||||
tc.ExternalSecret.Spec.Data = []esv1alpha1.ExternalSecretData{
|
||||
{
|
||||
SecretKey: "singlefoo",
|
||||
RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
|
||||
Key: "foo",
|
||||
},
|
||||
},
|
||||
{
|
||||
SecretKey: "singlebaz",
|
||||
RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
|
||||
Key: "baz",
|
||||
},
|
||||
},
|
||||
{
|
||||
SecretKey: "singlejson",
|
||||
RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
|
||||
Key: "json",
|
||||
},
|
||||
},
|
||||
}
|
||||
tc.ExternalSecret.Spec.DataFrom = []esv1alpha1.ExternalSecretDataRemoteRef{
|
||||
{
|
||||
Key: "map",
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
6
go.mod
6
go.mod
|
@ -40,8 +40,7 @@ require (
|
|||
github.com/IBM/go-sdk-core/v5 v5.9.1
|
||||
github.com/IBM/secrets-manager-go-sdk v1.0.31
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible
|
||||
github.com/Masterminds/sprig/v3 v3.2.2
|
||||
github.com/PaesslerAG/jsonpath v0.1.1
|
||||
github.com/ahmetb/gen-crd-api-reference-docs v0.3.0
|
||||
github.com/akeylesslabs/akeyless-go-cloud-id v0.3.2
|
||||
|
@ -98,6 +97,7 @@ require (
|
|||
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.1.1 // indirect
|
||||
github.com/PaesslerAG/gval v1.0.0 // indirect
|
||||
github.com/armon/go-metrics v0.3.10 // indirect
|
||||
github.com/armon/go-radix v1.0.0 // indirect
|
||||
|
@ -180,8 +180,10 @@ require (
|
|||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.0.1 // indirect
|
||||
github.com/ryanuber/go-glob v1.0.0 // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||
github.com/sony/gobreaker v0.4.2-0.20210216022020-dd874f9dd33b // indirect
|
||||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/spf13/cobra v1.2.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/stretchr/objx v0.2.0 // indirect
|
||||
|
|
14
go.sum
14
go.sum
|
@ -94,10 +94,10 @@ github.com/IBM/secrets-manager-go-sdk v1.0.31 h1:KRRyeEvlKkkZb90njgReOrK92+IyS6L
|
|||
github.com/IBM/secrets-manager-go-sdk v1.0.31/go.mod h1:0Juj6ER/LpDqJ49nw705MNyXSHsHodgztFdkXz5ttxs=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
||||
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8=
|
||||
github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
|
@ -517,11 +517,13 @@ github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKe
|
|||
github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I=
|
||||
github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
|
||||
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
|
@ -759,6 +761,8 @@ github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFo
|
|||
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
|
||||
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
|
@ -779,6 +783,7 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B
|
|||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
|
@ -898,6 +903,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
|||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
|
|
|
@ -56,7 +56,11 @@ func (r *Reconciler) applyTemplate(ctx context.Context, es *esv1alpha1.ExternalS
|
|||
}
|
||||
r.Log.V(1).Info("found template data", "tpl_data", tplMap)
|
||||
|
||||
err = template.Execute(tplMap, dataMap, secret)
|
||||
execute, err := template.EngineForVersion(es.Spec.Target.Template.EngineVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = execute(tplMap, dataMap, secret)
|
||||
if err != nil {
|
||||
return fmt.Errorf(errExecTpl, err)
|
||||
}
|
||||
|
|
|
@ -433,6 +433,9 @@ var _ = Describe("ExternalSecret controller", func() {
|
|||
"hihi": "ga",
|
||||
},
|
||||
},
|
||||
// We do not specify the engine version
|
||||
// it should default to v1 for alpha1
|
||||
// EngineVersion: esv1alpha1.TemplateEngineV1,
|
||||
Type: v1.SecretTypeOpaque,
|
||||
Data: map[string]string{
|
||||
targetProp: targetPropObj,
|
||||
|
@ -453,6 +456,23 @@ var _ = Describe("ExternalSecret controller", func() {
|
|||
}
|
||||
}
|
||||
|
||||
// when using a v2 template it should use the v2 engine version
|
||||
syncWithTemplateV2 := func(tc *testCase) {
|
||||
const secretVal = "someValue"
|
||||
tc.externalSecret.Spec.Target.Template = &esv1alpha1.ExternalSecretTemplate{
|
||||
Type: v1.SecretTypeOpaque,
|
||||
EngineVersion: esv1alpha1.TemplateEngineV2,
|
||||
Data: map[string]string{
|
||||
targetProp: "{{ .targetProperty | upper }} was templated",
|
||||
},
|
||||
}
|
||||
fakeProvider.WithGetSecret([]byte(secretVal), nil)
|
||||
tc.checkSecret = func(es *esv1alpha1.ExternalSecret, secret *v1.Secret) {
|
||||
// check values
|
||||
Expect(string(secret.Data[targetProp])).To(Equal(expectedSecretVal))
|
||||
}
|
||||
}
|
||||
|
||||
// secret should be synced with correct value precedence:
|
||||
// * template
|
||||
// * templateFrom
|
||||
|
@ -1046,6 +1066,7 @@ var _ = Describe("ExternalSecret controller", func() {
|
|||
Entry("should not resolve conflicts with creationPolicy=Merge", mergeWithConflict),
|
||||
Entry("should not update unchanged secret using creationPolicy=Merge", mergeWithSecretNoChange),
|
||||
Entry("should sync with template", syncWithTemplate),
|
||||
Entry("should sync with template engine v2", syncWithTemplateV2),
|
||||
Entry("should sync template with correct value precedence", syncWithTemplatePrecedence),
|
||||
Entry("should refresh secret from template", refreshWithTemplate),
|
||||
Entry("should be able to use only metadata from template", onlyMetadataFromTemplate),
|
||||
|
|
|
@ -26,7 +26,7 @@ import (
|
|||
"strings"
|
||||
tpl "text/template"
|
||||
|
||||
"github.com/Masterminds/sprig"
|
||||
"github.com/Masterminds/sprig/v3"
|
||||
"github.com/PaesslerAG/jsonpath"
|
||||
"gopkg.in/yaml.v3"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
@ -36,7 +36,7 @@ import (
|
|||
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
||||
"github.com/external-secrets/external-secrets/pkg/provider"
|
||||
"github.com/external-secrets/external-secrets/pkg/provider/schema"
|
||||
"github.com/external-secrets/external-secrets/pkg/template"
|
||||
"github.com/external-secrets/external-secrets/pkg/template/v1"
|
||||
)
|
||||
|
||||
// Provider satisfies the provider interface.
|
||||
|
|
36
pkg/template/engine.go
Normal file
36
pkg/template/engine.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
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.
|
||||
limitations under the License.
|
||||
*/
|
||||
package template
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
||||
esapi "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
|
||||
v1 "github.com/external-secrets/external-secrets/pkg/template/v1"
|
||||
v2 "github.com/external-secrets/external-secrets/pkg/template/v2"
|
||||
)
|
||||
|
||||
type ExecFunc func(tpl, data map[string][]byte, secret *corev1.Secret) error
|
||||
|
||||
func EngineForVersion(version esapi.TemplateEngineVersion) (ExecFunc, error) {
|
||||
switch version {
|
||||
case esapi.TemplateEngineV1:
|
||||
return v1.Execute, nil
|
||||
case esapi.TemplateEngineV2:
|
||||
return v2.Execute, nil
|
||||
}
|
||||
|
||||
// in case we run with a old v1alpha1 CRD
|
||||
// we must return v1 as default
|
||||
return v1.Execute, nil
|
||||
}
|
|
@ -2,9 +2,7 @@
|
|||
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.
|
188
pkg/template/v2/template.go
Normal file
188
pkg/template/v2/template.go
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
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 template
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
tpl "text/template"
|
||||
|
||||
"github.com/Masterminds/sprig/v3"
|
||||
"github.com/lestrrat-go/jwx/jwk"
|
||||
"github.com/youmark/pkcs8"
|
||||
"golang.org/x/crypto/pkcs12"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
var tplFuncs = tpl.FuncMap{
|
||||
"pkcs12key": pkcs12key,
|
||||
"pkcs12keyPass": pkcs12keyPass,
|
||||
"pkcs12cert": pkcs12cert,
|
||||
"pkcs12certPass": pkcs12certPass,
|
||||
|
||||
"pemPrivateKey": pemPrivateKey,
|
||||
"pemCertificate": pemCertificate,
|
||||
|
||||
"jwkPublicKeyPem": jwkPublicKeyPem,
|
||||
"jwkPrivateKeyPem": jwkPrivateKeyPem,
|
||||
}
|
||||
|
||||
// So other templating calls can use the same extra functions.
|
||||
func FuncMap() tpl.FuncMap {
|
||||
return tplFuncs
|
||||
}
|
||||
|
||||
const (
|
||||
errParse = "unable to parse template at key %s: %s"
|
||||
errExecute = "unable to execute template at key %s: %s"
|
||||
errDecodePKCS12WithPass = "unable to decode pkcs12 with password: %s"
|
||||
errConvertPrivKey = "unable to convert pkcs12 private key: %s"
|
||||
errDecodeCertWithPass = "unable to decode pkcs12 certificate with password: %s"
|
||||
errEncodePEMKey = "unable to encode pem private key: %s"
|
||||
errEncodePEMCert = "unable to encode pem certificate: %s"
|
||||
)
|
||||
|
||||
func init() {
|
||||
fmt.Printf("calling init in v2 pkg")
|
||||
sprigFuncs := sprig.TxtFuncMap()
|
||||
delete(sprigFuncs, "env")
|
||||
delete(sprigFuncs, "expandenv")
|
||||
|
||||
for k, v := range sprigFuncs {
|
||||
fmt.Printf("adding func %s\n", k)
|
||||
tplFuncs[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// Execute renders the secret data as template. If an error occurs processing is stopped immediately.
|
||||
func Execute(tpl, data map[string][]byte, secret *corev1.Secret) error {
|
||||
if tpl == nil {
|
||||
return nil
|
||||
}
|
||||
for k, v := range tpl {
|
||||
val, err := execute(k, string(v), data)
|
||||
if err != nil {
|
||||
return fmt.Errorf(errExecute, k, err)
|
||||
}
|
||||
secret.Data[k] = val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func execute(k, val string, data map[string][]byte) ([]byte, error) {
|
||||
strValData := make(map[string]string, len(data))
|
||||
for k := range data {
|
||||
strValData[k] = string(data[k])
|
||||
}
|
||||
|
||||
t, err := tpl.New(k).
|
||||
Funcs(tplFuncs).
|
||||
Parse(val)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(errParse, k, err)
|
||||
}
|
||||
buf := bytes.NewBuffer(nil)
|
||||
err = t.Execute(buf, strValData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(errExecute, k, err)
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func pkcs12keyPass(pass, input string) (string, error) {
|
||||
key, _, err := pkcs12.Decode([]byte(input), pass)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf(errDecodePKCS12WithPass, err)
|
||||
}
|
||||
kb, err := pkcs8.ConvertPrivateKeyToPKCS8(key)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf(errConvertPrivKey, err)
|
||||
}
|
||||
return string(kb), nil
|
||||
}
|
||||
|
||||
func pkcs12key(input string) (string, error) {
|
||||
return pkcs12keyPass("", input)
|
||||
}
|
||||
|
||||
func pkcs12certPass(pass, input string) (string, error) {
|
||||
_, cert, err := pkcs12.Decode([]byte(input), pass)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf(errDecodeCertWithPass, err)
|
||||
}
|
||||
return string(cert.Raw), nil
|
||||
}
|
||||
|
||||
func pkcs12cert(input string) (string, error) {
|
||||
return pkcs12certPass("", input)
|
||||
}
|
||||
|
||||
func jwkPublicKeyPem(jwkjson string) (string, error) {
|
||||
k, err := jwk.ParseKey([]byte(jwkjson))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var rawkey interface{}
|
||||
err = k.Raw(&rawkey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
mpk, err := x509.MarshalPKIXPublicKey(rawkey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return pemEncode(string(mpk), "PUBLIC KEY")
|
||||
}
|
||||
|
||||
func jwkPrivateKeyPem(jwkjson string) (string, error) {
|
||||
k, err := jwk.ParseKey([]byte(jwkjson))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var mpk []byte
|
||||
var pk interface{}
|
||||
err = k.Raw(&pk)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
mpk, err = x509.MarshalPKCS8PrivateKey(pk)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return pemEncode(string(mpk), "PRIVATE KEY")
|
||||
}
|
||||
|
||||
func pemEncode(thing, kind string) (string, error) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
err := pem.Encode(buf, &pem.Block{Type: kind, Bytes: []byte(thing)})
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
func pemPrivateKey(key string) (string, error) {
|
||||
res, err := pemEncode(key, "PRIVATE KEY")
|
||||
if err != nil {
|
||||
return res, fmt.Errorf(errEncodePEMKey, err)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func pemCertificate(cert string) (string, error) {
|
||||
res, err := pemEncode(cert, "CERTIFICATE")
|
||||
if err != nil {
|
||||
return res, fmt.Errorf(errEncodePEMCert, err)
|
||||
}
|
||||
return res, nil
|
||||
}
|
384
pkg/template/v2/template_test.go
Normal file
384
pkg/template/v2/template_test.go
Normal file
|
@ -0,0 +1,384 @@
|
|||
/*
|
||||
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 template_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
||||
"github.com/external-secrets/external-secrets/pkg/template/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
pkcs12ContentNoPass = `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`
|
||||
pkcs12ContentWithPass = `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`
|
||||
pkcs12Cert = `-----BEGIN CERTIFICATE-----
|
||||
MIIDHTCCAgWgAwIBAgIRAKC4yxy9QGocND+6avTf7BgwDQYJKoZIhvcNAQELBQAw
|
||||
EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0yMTAzMjAyMDA4MDhaFw0yMTAzMjAyMDM4
|
||||
MDhaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
|
||||
ggEKAoIBAQC3o6/JdZEqNbqNRkopHhJtJG5c4qS5d0tQ/kZYpfD/v/izAYum4Nzj
|
||||
aG15owr92/11W0pxPUliRLti3y6iScTs+ofm2D7p4UXj/Fnho/2xoWSOoWAodgvW
|
||||
Y8jh8A0LQALZiV/9QsrJdXZdS47DYZLsQ3z9yFC/CdXkg1l7AQ3fIVGKdrQBr9kE
|
||||
1gEDqnKfRxXI8DEQKXr+CKPUwCAytegmy0SHp53zNAvY+kopHytzmJpXLoEhxq4e
|
||||
ugHe52vXHdh/HJ9VjNp0xOH1waAgAGxHlltCW0PVd5AJ0SXROBS/a3V9sZCbCrJa
|
||||
YOOonQSEswveSv6PcG9AHvpNPot2Xs6hAgMBAAGjbjBsMA4GA1UdDwEB/wQEAwIC
|
||||
pDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
|
||||
BBR00805mrpoonp95RmC3B6oLl+cGTAVBgNVHREEDjAMggpnb29ibGUuY29tMA0G
|
||||
CSqGSIb3DQEBCwUAA4IBAQAipc1b6JrEDayPjpz5GM5krcI8dCWVd8re0a9bGjjN
|
||||
ioWGlu/eTr5El0ffwCNZ2WLmL9rewfHf/bMvYz3ioFZJ2OTxfazqYXNggQz6cMfa
|
||||
lbedDCdt5XLVX2TyerGvFram+9Uyvk3l0uM7rZnwAmdirG4Tv94QRaD3q4xTj/c0
|
||||
mv+AggtK0aRFb9o47z/BypLdk5mhbf3Mmr88C8XBzEnfdYyf4JpTlZrYLBmDCu5d
|
||||
9RLLsjXxhag8xqMtd1uLUM8XOTGzVWacw8iGY+CTtBKqyA+AE6/bDwZvEwVtsKtC
|
||||
QJ85ioEpy00NioqcF0WyMZH80uMsPycfpnl5uF7RkW8u
|
||||
-----END CERTIFICATE-----
|
||||
`
|
||||
pkcs12Key = `-----BEGIN PRIVATE KEY-----
|
||||
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC3o6/JdZEqNbqN
|
||||
RkopHhJtJG5c4qS5d0tQ/kZYpfD/v/izAYum4NzjaG15owr92/11W0pxPUliRLti
|
||||
3y6iScTs+ofm2D7p4UXj/Fnho/2xoWSOoWAodgvWY8jh8A0LQALZiV/9QsrJdXZd
|
||||
S47DYZLsQ3z9yFC/CdXkg1l7AQ3fIVGKdrQBr9kE1gEDqnKfRxXI8DEQKXr+CKPU
|
||||
wCAytegmy0SHp53zNAvY+kopHytzmJpXLoEhxq4eugHe52vXHdh/HJ9VjNp0xOH1
|
||||
waAgAGxHlltCW0PVd5AJ0SXROBS/a3V9sZCbCrJaYOOonQSEswveSv6PcG9AHvpN
|
||||
Pot2Xs6hAgMBAAECggEACTGPrmVNZDCWa1Y2hkJ0J7SoNcw+9O4M/jwMp4l/PD6P
|
||||
I98S78LYLCZhPLK17SmjUcnFO1AXKW1JeFS2D/fjfP256guvcqQNjLFoioxcOhVb
|
||||
ZGyd1Mi8JPqP5wfOj16gBeYDwTkjz9wqldcfiZaL9XoXetkZecbzR2JwC2FtIVuC
|
||||
0njTjMNYpaBKnoLb8OTR0EQz7lYEo2MkQiWryz8wseONnFmdfh18p+p10YgCbuCH
|
||||
qesrWfDLLxaxZelNtDhDngg9LoCLmarYy7BgShacmUEgJTZ/x3xFC75thK3ln0OY
|
||||
+ktTgvVotYYaZi7qAjQiEsTvkTAPg5RMpQLd2UIWsQKBgQDCBp+1vURbwGzmTNUg
|
||||
HMipD6WDFdLc9DCacx6+ZqsEPTMWQbCpVZrDKiY0Rjt5F+xOCyMr00J5RDJXRC0G
|
||||
+L7NcJdywOFutT7vB+cmETg7l/6PHweNYBnE66706eTL/KVYZMi4tEinarPWhHmL
|
||||
jasfdLANtpDjdWkRt299TkPRbQKBgQDyS8Rr7KZdv04Csqkf+ASmiJpT5R6Y72kc
|
||||
3XYpKETyB2FyPZkuh/zInMut9SkkSI9O/jA3zf956jj6sF1DHvp7T8KkIp5OAQeD
|
||||
J9AF65m2MnZfHFUeJ6ZQsggwMWqrD0ycIWP7YWtiBHH+D1wGkjYrssq+bvG/yNpA
|
||||
LtqdKq9lhQKBgQCZA2hIhy61vRckuEsLvCdzTGeW7UsR/XGnHEqOlaEhArKbRsrv
|
||||
gBdA+qiOaSTV5svw8E+YbE7sG6AnuhhYeyreEYEeeoZOLJmpIG5mUwYp2UBj1nC6
|
||||
SaOI7OVZOGu7g09SWokBQQxbG4cgEfFY4Sym7fs5lVTGTP3Dfwppo6NQMQKBgQCo
|
||||
J5NDP3Lafwk58BpV+H/pv8YzUUDh7M2rXbtCpxLqUdr8OOnVlEUISWFF8m5CIyVq
|
||||
MhjuscWLK9Wtjba7/YTjDaDM3sW05xv6lyfU5ATCoNTr/zLHgcb4HAZ4w+L+otiN
|
||||
RtMnxB2NYf5mzuwUF2cG/secUEzwyAlIH/xStSwTLQKBgQCRvqF+rqxnegoOgwVW
|
||||
qrWPv06wXD8dW2FlPpY5GXqA0l6erSK3YsQQToRmbem9ibPD7bd5P4gNbWfxwK4C
|
||||
Wt+1Rcb8OrDhDJbYz85bXBnPecKp4EN0b9SHO0/dsCqn2w30emc+9T/4m1ZDkpBd
|
||||
BixHvI/EJ8YK3ta5WdJWKC6hnA==
|
||||
-----END PRIVATE KEY-----
|
||||
`
|
||||
jwkPubRSA = `{"kid":"ex","kty":"RSA","key_ops":["sign","verify","wrapKey","unwrapKey","encrypt","decrypt"],"n":"p2VQo8qCfWAZmdWBVaYuYb-a-tWWm78K6Sr9poCvNcmv8rUPSLACxitQWR8gZaSH1DklVkqz-Ed8Cdlf8lkDg4Ex5tkB64jRdC1Uvn4CDpOH6cp-N2s8hTFLqy9_YaDmyQS7HiqthOi9oVjil1VMeWfaAbClGtFt6UnKD0Vb_DvLoWYQSqlhgBArFJi966b4E1pOq5Ad02K8pHBDThlIIx7unibLehhDU6q3DCwNH_OOLx6bgNtmvGYJDd1cywpkLQ3YzNCUPWnfMBJRP3iQP_WI21uP6cvo0DqBPBM4wvVzHbCT0vnIflwkbgEWkq1FprqAitZlop9KjLqzjp9vyQ","e":"AQAB"}`
|
||||
jwkPubRSAPKIX = `-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp2VQo8qCfWAZmdWBVaYu
|
||||
Yb+a+tWWm78K6Sr9poCvNcmv8rUPSLACxitQWR8gZaSH1DklVkqz+Ed8Cdlf8lkD
|
||||
g4Ex5tkB64jRdC1Uvn4CDpOH6cp+N2s8hTFLqy9/YaDmyQS7HiqthOi9oVjil1VM
|
||||
eWfaAbClGtFt6UnKD0Vb/DvLoWYQSqlhgBArFJi966b4E1pOq5Ad02K8pHBDThlI
|
||||
Ix7unibLehhDU6q3DCwNH/OOLx6bgNtmvGYJDd1cywpkLQ3YzNCUPWnfMBJRP3iQ
|
||||
P/WI21uP6cvo0DqBPBM4wvVzHbCT0vnIflwkbgEWkq1FprqAitZlop9KjLqzjp9v
|
||||
yQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
`
|
||||
jwkPrivRSA = `{"kty" : "RSA","kid" : "cc34c0a0-bd5a-4a3c-a50d-a2a7db7643df","use" : "sig","n" : "pjdss8ZaDfEH6K6U7GeW2nxDqR4IP049fk1fK0lndimbMMVBdPv_hSpm8T8EtBDxrUdi1OHZfMhUixGaut-3nQ4GG9nM249oxhCtxqqNvEXrmQRGqczyLxuh-fKn9Fg--hS9UpazHpfVAFnB5aCfXoNhPuI8oByyFKMKaOVgHNqP5NBEqabiLftZD3W_lsFCPGuzr4Vp0YS7zS2hDYScC2oOMu4rGU1LcMZf39p3153Cq7bS2Xh6Y-vw5pwzFYZdjQxDn8x8BG3fJ6j8TGLXQsbKH1218_HcUJRvMwdpbUQG5nvA2GXVqLqdwp054Lzk9_B_f1lVrmOKuHjTNHq48w","e" : "AQAB","d" : "ksDmucdMJXkFGZxiomNHnroOZxe8AmDLDGO1vhs-POa5PZM7mtUPonxwjVmthmpbZzla-kg55OFfO7YcXhg-Hm2OWTKwm73_rLh3JavaHjvBqsVKuorX3V3RYkSro6HyYIzFJ1Ek7sLxbjDRcDOj4ievSX0oN9l-JZhaDYlPlci5uJsoqro_YrE0PRRWVhtGynd-_aWgQv1YzkfZuMD-hJtDi1Im2humOWxA4eZrFs9eG-whXcOvaSwO4sSGbS99ecQZHM2TcdXeAs1PvjVgQ_dKnZlGN3lTWoWfQP55Z7Tgt8Nf1q4ZAKd-NlMe-7iqCFfsnFwXjSiaOa2CRGZn-Q","p" : "4A5nU4ahEww7B65yuzmGeCUUi8ikWzv1C81pSyUKvKzu8CX41hp9J6oRaLGesKImYiuVQK47FhZ--wwfpRwHvSxtNU9qXb8ewo-BvadyO1eVrIk4tNV543QlSe7pQAoJGkxCia5rfznAE3InKF4JvIlchyqs0RQ8wx7lULqwnn0","q" : "ven83GM6SfrmO-TBHbjTk6JhP_3CMsIvmSdo4KrbQNvp4vHO3w1_0zJ3URkmkYGhz2tgPlfd7v1l2I6QkIh4Bumdj6FyFZEBpxjE4MpfdNVcNINvVj87cLyTRmIcaGxmfylY7QErP8GFA-k4UoH_eQmGKGK44TRzYj5hZYGWIC8","dp" : "lmmU_AG5SGxBhJqb8wxfNXDPJjf__i92BgJT2Vp4pskBbr5PGoyV0HbfUQVMnw977RONEurkR6O6gxZUeCclGt4kQlGZ-m0_XSWx13v9t9DIbheAtgVJ2mQyVDvK4m7aRYlEceFh0PsX8vYDS5o1txgPwb3oXkPTtrmbAGMUBpE","dq" : "mxRTU3QDyR2EnCv0Nl0TCF90oliJGAHR9HJmBe__EjuCBbwHfcT8OG3hWOv8vpzokQPRl5cQt3NckzX3fs6xlJN4Ai2Hh2zduKFVQ2p-AF2p6Yfahscjtq-GY9cB85NxLy2IXCC0PF--Sq9LOrTE9QV988SJy_yUrAjcZ5MmECk","qi" : "ldHXIrEmMZVaNwGzDF9WG8sHj2mOZmQpw9yrjLK9hAsmsNr5LTyqWAqJIYZSwPTYWhY4nu2O0EY9G9uYiqewXfCKw_UngrJt8Xwfq1Zruz0YY869zPN4GiE9-9rzdZB33RBw8kIOquY3MK74FMwCihYx_LiU2YTHkaoJ3ncvtvg"}`
|
||||
jwkPrivRSAPKCS8 = `-----BEGIN PRIVATE KEY-----
|
||||
MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQCmN2yzxloN8Qfo
|
||||
rpTsZ5bafEOpHgg/Tj1+TV8rSWd2KZswxUF0+/+FKmbxPwS0EPGtR2LU4dl8yFSL
|
||||
EZq637edDgYb2czbj2jGEK3Gqo28ReuZBEapzPIvG6H58qf0WD76FL1SlrMel9UA
|
||||
WcHloJ9eg2E+4jygHLIUowpo5WAc2o/k0ESppuIt+1kPdb+WwUI8a7OvhWnRhLvN
|
||||
LaENhJwLag4y7isZTUtwxl/f2nfXncKrttLZeHpj6/DmnDMVhl2NDEOfzHwEbd8n
|
||||
qPxMYtdCxsofXbXz8dxQlG8zB2ltRAbme8DYZdWoup3CnTngvOT38H9/WVWuY4q4
|
||||
eNM0erjzAgMBAAECggEBAJLA5rnHTCV5BRmcYqJjR566DmcXvAJgywxjtb4bPjzm
|
||||
uT2TO5rVD6J8cI1ZrYZqW2c5WvpIOeThXzu2HF4YPh5tjlkysJu9/6y4dyWr2h47
|
||||
warFSrqK191d0WJEq6Oh8mCMxSdRJO7C8W4w0XAzo+Inr0l9KDfZfiWYWg2JT5XI
|
||||
ubibKKq6P2KxND0UVlYbRsp3fv2loEL9WM5H2bjA/oSbQ4tSJtobpjlsQOHmaxbP
|
||||
XhvsIV3Dr2ksDuLEhm0vfXnEGRzNk3HV3gLNT741YEP3Sp2ZRjd5U1qFn0D+eWe0
|
||||
4LfDX9auGQCnfjZTHvu4qghX7JxcF40omjmtgkRmZ/kCgYEA4A5nU4ahEww7B65y
|
||||
uzmGeCUUi8ikWzv1C81pSyUKvKzu8CX41hp9J6oRaLGesKImYiuVQK47FhZ++wwf
|
||||
pRwHvSxtNU9qXb8ewo+BvadyO1eVrIk4tNV543QlSe7pQAoJGkxCia5rfznAE3In
|
||||
KF4JvIlchyqs0RQ8wx7lULqwnn0CgYEAven83GM6SfrmO+TBHbjTk6JhP/3CMsIv
|
||||
mSdo4KrbQNvp4vHO3w1/0zJ3URkmkYGhz2tgPlfd7v1l2I6QkIh4Bumdj6FyFZEB
|
||||
pxjE4MpfdNVcNINvVj87cLyTRmIcaGxmfylY7QErP8GFA+k4UoH/eQmGKGK44TRz
|
||||
Yj5hZYGWIC8CgYEAlmmU/AG5SGxBhJqb8wxfNXDPJjf//i92BgJT2Vp4pskBbr5P
|
||||
GoyV0HbfUQVMnw977RONEurkR6O6gxZUeCclGt4kQlGZ+m0/XSWx13v9t9DIbheA
|
||||
tgVJ2mQyVDvK4m7aRYlEceFh0PsX8vYDS5o1txgPwb3oXkPTtrmbAGMUBpECgYEA
|
||||
mxRTU3QDyR2EnCv0Nl0TCF90oliJGAHR9HJmBe//EjuCBbwHfcT8OG3hWOv8vpzo
|
||||
kQPRl5cQt3NckzX3fs6xlJN4Ai2Hh2zduKFVQ2p+AF2p6Yfahscjtq+GY9cB85Nx
|
||||
Ly2IXCC0PF++Sq9LOrTE9QV988SJy/yUrAjcZ5MmECkCgYEAldHXIrEmMZVaNwGz
|
||||
DF9WG8sHj2mOZmQpw9yrjLK9hAsmsNr5LTyqWAqJIYZSwPTYWhY4nu2O0EY9G9uY
|
||||
iqewXfCKw/UngrJt8Xwfq1Zruz0YY869zPN4GiE9+9rzdZB33RBw8kIOquY3MK74
|
||||
FMwCihYx/LiU2YTHkaoJ3ncvtvg=
|
||||
-----END PRIVATE KEY-----
|
||||
`
|
||||
jwkPubEC = `{"kid":"https://kv-test-mj.vault.azure.net/keys/ec-p-521/e3d0e9c179b54988860c69c6ae172c65","kty":"EC","key_ops":["sign","verify"],"crv":"P-521","x":"AedOAtb7H7Oz1C_cPKI_R4CN_eai5nteY6KFW07FOoaqgQfVCSkQDK22fCOiMT_28c8LZYJRsiIFz_IIbQUW7bXj","y":"AOnchHnmBphIWXvanmMAmcCDkaED6ycW8GsAl9fQ43BMVZTqcTkJYn6vGnhn7MObizmkNSmgZYTwG-vZkIg03HHs"}`
|
||||
jwkPubECPKIX = `-----BEGIN PUBLIC KEY-----
|
||||
MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQB504C1vsfs7PUL9w8oj9HgI395qLm
|
||||
e15jooVbTsU6hqqBB9UJKRAMrbZ8I6IxP/bxzwtlglGyIgXP8ghtBRbtteMA6dyE
|
||||
eeYGmEhZe9qeYwCZwIORoQPrJxbwawCX19DjcExVlOpxOQlifq8aeGfsw5uLOaQ1
|
||||
KaBlhPAb69mQiDTccew=
|
||||
-----END PUBLIC KEY-----
|
||||
`
|
||||
jwkPrivEC = `{"kty": "EC","kid": "rie3pHe8u8gjSa0IaJfqk7_iEfHeYfDYx-Bqi7vQc0s","crv": "P-256","x": "fDjg3Nq4jPf8IOZ0277aPVal_8iXySnzLUJAZghUzZM","y": "d863PeyBOK_Q4duiSmWwgIRzi1RPlFZTR-vACMlPg-Q","d": "jJs5xsoHUetdMabtt8H2KyX5T92nGul1chFeMT5hlr0"}`
|
||||
jwkPrivECPKCS8 = `-----BEGIN PRIVATE KEY-----
|
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgjJs5xsoHUetdMabt
|
||||
t8H2KyX5T92nGul1chFeMT5hlr2hRANCAAR8OODc2riM9/wg5nTbvto9VqX/yJfJ
|
||||
KfMtQkBmCFTNk3fOtz3sgTiv0OHbokplsICEc4tUT5RWU0frwAjJT4Pk
|
||||
-----END PRIVATE KEY-----
|
||||
`
|
||||
)
|
||||
|
||||
func TestExecute(t *testing.T) {
|
||||
tbl := []struct {
|
||||
name string
|
||||
tpl map[string][]byte
|
||||
data map[string][]byte
|
||||
expetedData map[string][]byte
|
||||
expErr string
|
||||
}{
|
||||
{
|
||||
name: "test empty",
|
||||
tpl: nil,
|
||||
data: nil,
|
||||
},
|
||||
{
|
||||
name: "b64dec func",
|
||||
tpl: map[string][]byte{
|
||||
"foo": []byte("{{ .secret | b64dec }}"),
|
||||
},
|
||||
data: map[string][]byte{
|
||||
"secret": []byte("MTIzNA=="),
|
||||
},
|
||||
expetedData: map[string][]byte{
|
||||
"foo": []byte("1234"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fromJSON func",
|
||||
tpl: map[string][]byte{
|
||||
"foo": []byte("{{ $var := .secret | fromJson }}{{ $var.foo }}"),
|
||||
},
|
||||
data: map[string][]byte{
|
||||
"secret": []byte(`{"foo": "bar"}`),
|
||||
},
|
||||
expetedData: map[string][]byte{
|
||||
"foo": []byte("bar"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "from & toJSON func",
|
||||
tpl: map[string][]byte{
|
||||
"foo": []byte("{{ $var := .secret | fromJson }}{{ $var.foo | toJson }}"),
|
||||
},
|
||||
data: map[string][]byte{
|
||||
"secret": []byte(`{"foo": {"baz":"bang"}}`),
|
||||
},
|
||||
expetedData: map[string][]byte{
|
||||
"foo": []byte(`{"baz":"bang"}`),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "use sprig functions",
|
||||
tpl: map[string][]byte{
|
||||
"foo": []byte(`{{ .path | ext }}`), // TODO: this is a breaking change
|
||||
},
|
||||
data: map[string][]byte{
|
||||
"path": []byte(`foo/bar/baz.exe`),
|
||||
},
|
||||
expetedData: map[string][]byte{
|
||||
"foo": []byte(`.exe`),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiline template",
|
||||
tpl: map[string][]byte{
|
||||
"cfg": []byte(`
|
||||
datasources:
|
||||
- name: Graphite
|
||||
type: graphite
|
||||
access: proxy
|
||||
url: http://localhost:8080
|
||||
password: "{{ .password }}"
|
||||
user: "{{ .user }}"`),
|
||||
},
|
||||
data: map[string][]byte{
|
||||
"user": []byte(`foobert`),
|
||||
"password": []byte("harharhar"),
|
||||
},
|
||||
expetedData: map[string][]byte{
|
||||
"cfg": []byte(`
|
||||
datasources:
|
||||
- name: Graphite
|
||||
type: graphite
|
||||
access: proxy
|
||||
url: http://localhost:8080
|
||||
password: "harharhar"
|
||||
user: "foobert"`),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "base64 pipeline",
|
||||
tpl: map[string][]byte{
|
||||
"foo": []byte(`{{ "123412341234" | b64enc | b64dec }}`),
|
||||
},
|
||||
data: map[string][]byte{},
|
||||
expetedData: map[string][]byte{
|
||||
"foo": []byte("123412341234"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "base64 pkcs12 extract",
|
||||
tpl: map[string][]byte{
|
||||
"key": []byte(`{{ .secret | b64dec | pkcs12key | pemPrivateKey }}`),
|
||||
"cert": []byte(`{{ .secret | b64dec | pkcs12cert | pemCertificate }}`),
|
||||
},
|
||||
data: map[string][]byte{
|
||||
"secret": []byte(pkcs12ContentNoPass),
|
||||
},
|
||||
expetedData: map[string][]byte{
|
||||
"key": []byte(pkcs12Key),
|
||||
"cert": []byte(pkcs12Cert),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "base64 pkcs12 extract with password",
|
||||
tpl: map[string][]byte{
|
||||
"key": []byte(`{{ .secret | b64dec | pkcs12keyPass "123456" | pemPrivateKey }}`),
|
||||
"cert": []byte(`{{ .secret | b64dec | pkcs12certPass "123456" | pemCertificate }}`),
|
||||
},
|
||||
data: map[string][]byte{
|
||||
"secret": []byte(pkcs12ContentWithPass),
|
||||
},
|
||||
expetedData: map[string][]byte{
|
||||
"key": []byte(pkcs12Key),
|
||||
"cert": []byte(pkcs12Cert),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "base64 decode error",
|
||||
tpl: map[string][]byte{
|
||||
"key": []byte(`{{ .example | b64dec }}`),
|
||||
},
|
||||
data: map[string][]byte{
|
||||
"example": []byte("iam_no_base64"),
|
||||
},
|
||||
expErr: "", // silent error
|
||||
},
|
||||
{
|
||||
name: "pkcs12 key wrong password",
|
||||
tpl: map[string][]byte{
|
||||
"key": []byte(`{{ .secret | b64dec | pkcs12keyPass "wrong" | pemPrivateKey }}`),
|
||||
},
|
||||
data: map[string][]byte{
|
||||
"secret": []byte(pkcs12ContentWithPass),
|
||||
},
|
||||
expErr: "unable to decode pkcs12",
|
||||
},
|
||||
{
|
||||
name: "pkcs12 cert wrong password",
|
||||
tpl: map[string][]byte{
|
||||
"cert": []byte(`{{ .secret | b64dec | pkcs12certPass "wrong" | pemCertificate }}`),
|
||||
},
|
||||
data: map[string][]byte{
|
||||
"secret": []byte(pkcs12ContentWithPass),
|
||||
},
|
||||
expErr: "unable to decode pkcs12",
|
||||
},
|
||||
{
|
||||
name: "fromJSON error",
|
||||
tpl: map[string][]byte{
|
||||
"key": []byte(`{{ "{ # no json # }" | fromJson }}`),
|
||||
},
|
||||
data: map[string][]byte{},
|
||||
expErr: "", // silent error
|
||||
},
|
||||
{
|
||||
name: "template syntax error",
|
||||
tpl: map[string][]byte{
|
||||
"key": []byte(`{{ #xx }}`),
|
||||
},
|
||||
data: map[string][]byte{},
|
||||
expErr: "unable to parse template",
|
||||
},
|
||||
{
|
||||
name: "jwk rsa pub pem",
|
||||
tpl: map[string][]byte{
|
||||
"fn": []byte(`{{ .secret | jwkPublicKeyPem }}`),
|
||||
},
|
||||
data: map[string][]byte{
|
||||
"secret": []byte(jwkPubRSA),
|
||||
},
|
||||
expetedData: map[string][]byte{
|
||||
"fn": []byte(jwkPubRSAPKIX),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "jwk rsa priv pem",
|
||||
tpl: map[string][]byte{
|
||||
"fn": []byte(`{{ .secret | jwkPrivateKeyPem }}`),
|
||||
},
|
||||
data: map[string][]byte{
|
||||
"secret": []byte(jwkPrivRSA),
|
||||
},
|
||||
expetedData: map[string][]byte{
|
||||
"fn": []byte(jwkPrivRSAPKCS8),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "jwk ecdsa pub pem",
|
||||
tpl: map[string][]byte{
|
||||
"fn": []byte(`{{ .secret | jwkPublicKeyPem }}`),
|
||||
},
|
||||
data: map[string][]byte{
|
||||
"secret": []byte(jwkPubEC),
|
||||
},
|
||||
expetedData: map[string][]byte{
|
||||
"fn": []byte(jwkPubECPKIX),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "jwk ecdsa priv pem",
|
||||
tpl: map[string][]byte{
|
||||
"fn": []byte(`{{ .secret | jwkPrivateKeyPem }}`),
|
||||
},
|
||||
data: map[string][]byte{
|
||||
"secret": []byte(jwkPrivEC),
|
||||
},
|
||||
expetedData: map[string][]byte{
|
||||
"fn": []byte(jwkPrivECPKCS8),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i := range tbl {
|
||||
row := tbl[i]
|
||||
t.Run(row.name, func(t *testing.T) {
|
||||
sec := &corev1.Secret{
|
||||
Data: make(map[string][]byte),
|
||||
}
|
||||
err := template.Execute(row.tpl, row.data, sec)
|
||||
if !ErrorContains(err, row.expErr) {
|
||||
t.Errorf("unexpected error: %s, expected: %s", err, row.expErr)
|
||||
}
|
||||
if row.expetedData == nil {
|
||||
return
|
||||
}
|
||||
assert.EqualValues(t, row.expetedData, sec.Data)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func ErrorContains(out error, want string) bool {
|
||||
if out == nil {
|
||||
return want == ""
|
||||
}
|
||||
if want == "" {
|
||||
return false
|
||||
}
|
||||
return strings.Contains(out.Error(), want)
|
||||
}
|
Loading…
Reference in a new issue