From 03b0334fa0f895975f6086ebddd9cbff8637b430 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Fri, 28 Mar 2025 08:09:55 +0400 Subject: [PATCH] feat(k8s): pushsecret go templating --- .../kubernetes/infisical-push-secret-crd.mdx | 76 +++++++++++++++++++ k8-operator/api/v1alpha1/common.go | 14 +++- .../api/v1alpha1/infisicalpushsecret_types.go | 15 +++- .../api/v1alpha1/infisicalsecret_types.go | 10 --- .../api/v1alpha1/zz_generated.deepcopy.go | 74 +++++++++++------- ...ts.infisical.com_infisicalpushsecrets.yaml | 13 ++++ .../pushsecret/push-secret-with-template.yaml | 39 ++++++++++ .../{pushSecret.yaml => push-secret.yaml} | 0 .../infisicalpushsecret_helper.go | 69 ++++++++++++++--- .../infisicalsecret/infisicalsecret_helper.go | 19 +---- k8-operator/packages/util/template.go | 20 +++++ 11 files changed, 282 insertions(+), 67 deletions(-) create mode 100644 k8-operator/config/samples/crd/pushsecret/push-secret-with-template.yaml rename k8-operator/config/samples/crd/pushsecret/{pushSecret.yaml => push-secret.yaml} (100%) create mode 100644 k8-operator/packages/util/template.go diff --git a/docs/integrations/platforms/kubernetes/infisical-push-secret-crd.mdx b/docs/integrations/platforms/kubernetes/infisical-push-secret-crd.mdx index 67fc7f2a8..0d1ee3abf 100644 --- a/docs/integrations/platforms/kubernetes/infisical-push-secret-crd.mdx +++ b/docs/integrations/platforms/kubernetes/infisical-push-secret-crd.mdx @@ -401,6 +401,82 @@ After applying the InfisicalPushSecret CRD, you should notice that the secrets y +## Using templating to push secrets + +Pushing secrets to Infisical from the operator may not always be enough. +Templating is a useful utility of the Infisical secrets operator that allows you to use Go Templating to template the secrets you want to push to Infisical. +Using Go templates, you can format, combine, and create new key-value pairs of secrets that you want to push to Infisical. + + + + This property controls what secrets are included in your push to Infisica. + When set to `true`, all secrets included in the `push.secret.secretName` Kubernetes secret will be pushed to Infisical. + **Use this option when you would like to push all secrets to Infisical from the secrets operator, but want to template a subset of them.** + + When set to `false`, only secrets defined in the `push.secret.template.data` field of the template will be pushed to Infisical. + Use this option when you would like to push **only** a subset of secrets from the Kubernetes secret to Infisical. + + + Define secret keys and their corresponding templates. + Each data value uses a Golang template with access to all secrets defined in the `push.secret.secretName` Kubernetes secret. + + Secrets are structured as follows: + + ```go + type TemplateSecret struct { + Value string `json:"value"` + SecretPath string `json:"secretPath"` + } + ``` + + #### Example template configuration: + + ```yaml + # This example assumes that the `push-secret-demo` Kubernetes secret contains the following secrets: + # SITE_URL = "https://example.com" + # REGION = "us-east-1" + # OTHER_SECRET = "other-secret" + + push: + secret: + secretName: push-secret-demo + secretNamespace: default + template: + includeAllSecrets: true # Includes all secrets from the `push-secret-demo` Kubernetes secret + data: + SITE_URL: "{{ .SITE_URL.Value }}" + API_URL: "https://api.{{.SITE_URL.Value}}.{{.REGION.Value}}.com" # Will create a new secret in Infisical with the key `API_URL` with the value of the `SITE_URL` and `REGION` secrets + ``` + + To help transform your config map data further, the operator provides a set of built-in functions that you can use in your templates. + + ### Available templating functions + + + **Function name**: encodeBase64 + + **Description**: + Given a string, this function will encode the string as a base64 encoded string. + This function is useful when you want to store a string as a base64 encoded value in Infisical. + + **Returns**: The base64 encoded string. + + **Example**: + The example below assumes that the `PLAIN_KEY` secret is stored in your source secret as a plaintext string. + + ```yaml + push: + secret: + secretName: push-secret-demo + secretNamespace: default + template: + includeAllSecrets: true + data: + PLAIN_KEY: "{{ encodeBase64 .PLAIN_KEY.Value }}" # Will be stored in Infisical as a base64 encoded string + ``` + + + ## Applying the InfisicalPushSecret CRD to your cluster Once you have configured the `InfisicalPushSecret` CRD with the required fields, you can apply it to your cluster. diff --git a/k8-operator/api/v1alpha1/common.go b/k8-operator/api/v1alpha1/common.go index 5631984d1..2489b0b95 100644 --- a/k8-operator/api/v1alpha1/common.go +++ b/k8-operator/api/v1alpha1/common.go @@ -105,7 +105,7 @@ type ManagedKubeSecretConfig struct { // The template to transform the secret data // +kubebuilder:validation:Optional - Template *InfisicalSecretTemplate `json:"template,omitempty"` + Template *SecretTemplate `json:"template,omitempty"` } type ManagedKubeConfigMapConfig struct { @@ -127,5 +127,15 @@ type ManagedKubeConfigMapConfig struct { // The template to transform the secret data // +kubebuilder:validation:Optional - Template *InfisicalSecretTemplate `json:"template,omitempty"` + Template *SecretTemplate `json:"template,omitempty"` +} + +type SecretTemplate struct { + // This injects all retrieved secrets into the top level of your template. + // Secrets defined in the template will take precedence over the injected ones. + // +kubebuilder:validation:Optional + IncludeAllSecrets bool `json:"includeAllSecrets"` + // The template key values + // +kubebuilder:validation:Optional + Data map[string]string `json:"data,omitempty"` } diff --git a/k8-operator/api/v1alpha1/infisicalpushsecret_types.go b/k8-operator/api/v1alpha1/infisicalpushsecret_types.go index 9a1040868..5a7438881 100644 --- a/k8-operator/api/v1alpha1/infisicalpushsecret_types.go +++ b/k8-operator/api/v1alpha1/infisicalpushsecret_types.go @@ -16,9 +16,22 @@ type InfisicalPushSecretDestination struct { ProjectID string `json:"projectId"` } +type InfisicalPushSecretSecretSource struct { + // The name of the Kubernetes Secret + // +kubebuilder:validation:Required + SecretName string `json:"secretName"` + + // The name space where the Kubernetes Secret is located + // +kubebuilder:validation:Required + SecretNamespace string `json:"secretNamespace"` + + // +kubebuilder:validation:Optional + Template *SecretTemplate `json:"template,omitempty"` +} + type SecretPush struct { // +kubebuilder:validation:Required - Secret KubeSecretReference `json:"secret"` + Secret InfisicalPushSecretSecretSource `json:"secret"` } // InfisicalPushSecretSpec defines the desired state of InfisicalPushSecret diff --git a/k8-operator/api/v1alpha1/infisicalsecret_types.go b/k8-operator/api/v1alpha1/infisicalsecret_types.go index 8f871dfa6..e90c06938 100644 --- a/k8-operator/api/v1alpha1/infisicalsecret_types.go +++ b/k8-operator/api/v1alpha1/infisicalsecret_types.go @@ -116,16 +116,6 @@ type MachineIdentityScopeInWorkspace struct { Recursive bool `json:"recursive"` } -type InfisicalSecretTemplate struct { - // This injects all retrieved secrets into the top level of your template. - // Secrets defined in the template will take precedence over the injected ones. - // +kubebuilder:validation:Optional - IncludeAllSecrets bool `json:"includeAllSecrets"` - // The template key values - // +kubebuilder:validation:Optional - Data map[string]string `json:"data,omitempty"` -} - // InfisicalSecretSpec defines the desired state of InfisicalSecret type InfisicalSecretSpec struct { // +kubebuilder:validation:Optional diff --git a/k8-operator/api/v1alpha1/zz_generated.deepcopy.go b/k8-operator/api/v1alpha1/zz_generated.deepcopy.go index 11d864ad4..2ad97108d 100644 --- a/k8-operator/api/v1alpha1/zz_generated.deepcopy.go +++ b/k8-operator/api/v1alpha1/zz_generated.deepcopy.go @@ -383,7 +383,7 @@ func (in *InfisicalPushSecret) DeepCopyInto(out *InfisicalPushSecret) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec + in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) } @@ -452,12 +452,32 @@ func (in *InfisicalPushSecretList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InfisicalPushSecretSecretSource) DeepCopyInto(out *InfisicalPushSecretSecretSource) { + *out = *in + if in.Template != nil { + in, out := &in.Template, &out.Template + *out = new(SecretTemplate) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfisicalPushSecretSecretSource. +func (in *InfisicalPushSecretSecretSource) DeepCopy() *InfisicalPushSecretSecretSource { + if in == nil { + return nil + } + out := new(InfisicalPushSecretSecretSource) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *InfisicalPushSecretSpec) DeepCopyInto(out *InfisicalPushSecretSpec) { *out = *in out.Destination = in.Destination out.Authentication = in.Authentication - out.Push = in.Push + in.Push.DeepCopyInto(&out.Push) out.TLS = in.TLS } @@ -614,28 +634,6 @@ func (in *InfisicalSecretStatus) DeepCopy() *InfisicalSecretStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InfisicalSecretTemplate) DeepCopyInto(out *InfisicalSecretTemplate) { - *out = *in - if in.Data != nil { - in, out := &in.Data, &out.Data - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfisicalSecretTemplate. -func (in *InfisicalSecretTemplate) DeepCopy() *InfisicalSecretTemplate { - if in == nil { - return nil - } - out := new(InfisicalSecretTemplate) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KubeSecretReference) DeepCopyInto(out *KubeSecretReference) { *out = *in @@ -703,7 +701,7 @@ func (in *ManagedKubeConfigMapConfig) DeepCopyInto(out *ManagedKubeConfigMapConf *out = *in if in.Template != nil { in, out := &in.Template, &out.Template - *out = new(InfisicalSecretTemplate) + *out = new(SecretTemplate) (*in).DeepCopyInto(*out) } } @@ -723,7 +721,7 @@ func (in *ManagedKubeSecretConfig) DeepCopyInto(out *ManagedKubeSecretConfig) { *out = *in if in.Template != nil { in, out := &in.Template, &out.Template - *out = new(InfisicalSecretTemplate) + *out = new(SecretTemplate) (*in).DeepCopyInto(*out) } } @@ -741,7 +739,7 @@ func (in *ManagedKubeSecretConfig) DeepCopy() *ManagedKubeSecretConfig { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SecretPush) DeepCopyInto(out *SecretPush) { *out = *in - out.Secret = in.Secret + in.Secret.DeepCopyInto(&out.Secret) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretPush. @@ -769,6 +767,28 @@ func (in *SecretScopeInWorkspace) DeepCopy() *SecretScopeInWorkspace { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecretTemplate) DeepCopyInto(out *SecretTemplate) { + *out = *in + if in.Data != nil { + in, out := &in.Data, &out.Data + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretTemplate. +func (in *SecretTemplate) DeepCopy() *SecretTemplate { + if in == nil { + return nil + } + out := new(SecretTemplate) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ServiceAccountDetails) DeepCopyInto(out *ServiceAccountDetails) { *out = *in diff --git a/k8-operator/config/crd/bases/secrets.infisical.com_infisicalpushsecrets.yaml b/k8-operator/config/crd/bases/secrets.infisical.com_infisicalpushsecrets.yaml index a12ec9dbe..25fafd98a 100644 --- a/k8-operator/config/crd/bases/secrets.infisical.com_infisicalpushsecrets.yaml +++ b/k8-operator/config/crd/bases/secrets.infisical.com_infisicalpushsecrets.yaml @@ -137,6 +137,19 @@ spec: description: The name space where the Kubernetes Secret is located type: string + template: + properties: + data: + additionalProperties: + type: string + description: The template key values + type: object + includeAllSecrets: + description: This injects all retrieved secrets into the + top level of your template. Secrets defined in the template + will take precedence over the injected ones. + type: boolean + type: object required: - secretName - secretNamespace diff --git a/k8-operator/config/samples/crd/pushsecret/push-secret-with-template.yaml b/k8-operator/config/samples/crd/pushsecret/push-secret-with-template.yaml new file mode 100644 index 000000000..97fa9ace8 --- /dev/null +++ b/k8-operator/config/samples/crd/pushsecret/push-secret-with-template.yaml @@ -0,0 +1,39 @@ +apiVersion: secrets.infisical.com/v1alpha1 +kind: InfisicalPushSecret +metadata: + name: infisical-api-secret-sample-push +spec: + resyncInterval: 1m + hostAPI: http://localhost:8080/api + + # Optional, defaults to replacement. + updatePolicy: Replace # If set to replace, existing secrets inside Infisical will be replaced by the value of the PushSecret on sync. + + # Optional, defaults to no deletion. + deletionPolicy: Delete # If set to delete, the secret(s) inside Infisical managed by the operator, will be deleted if the InfisicalPushSecret CRD is deleted. + + destination: + projectId: + environmentSlug: + secretsPath: + + push: + secret: + secretName: push-secret-demo # Secret CRD + secretNamespace: default + template: + includeAllSecrets: false + data: + # Encodes the data so it's stored as base64 in Infisical. + API_KEY: "{{ .API_KEY.Value }}" + DATABASE_URL: "{{ .DATABASE_URL.Value }}" + ENCRYPTION_KEY: "{{ .ENCRYPTION_KEY.Value }}" + OTHER_VALUE: "{{ encodeBase64 .API_KEY.Value }} {{ encodeBase64 .DATABASE_URL.Value }} {{ encodeBase64 .ENCRYPTION_KEY.Value }}" + + # Only have one authentication method defined or you are likely to run into authentication issues. + # Remove all except one authentication method. + authentication: + universalAuth: + credentialsRef: + secretName: universal-auth-credentials + secretNamespace: default diff --git a/k8-operator/config/samples/crd/pushsecret/pushSecret.yaml b/k8-operator/config/samples/crd/pushsecret/push-secret.yaml similarity index 100% rename from k8-operator/config/samples/crd/pushsecret/pushSecret.yaml rename to k8-operator/config/samples/crd/pushsecret/push-secret.yaml diff --git a/k8-operator/controllers/infisicalpushsecret/infisicalpushsecret_helper.go b/k8-operator/controllers/infisicalpushsecret/infisicalpushsecret_helper.go index 47fc8e69b..1bcecfba0 100644 --- a/k8-operator/controllers/infisicalpushsecret/infisicalpushsecret_helper.go +++ b/k8-operator/controllers/infisicalpushsecret/infisicalpushsecret_helper.go @@ -1,16 +1,20 @@ package controllers import ( + "bytes" "context" "errors" "fmt" "strings" + "text/template" "github.com/Infisical/infisical/k8-operator/api/v1alpha1" "github.com/Infisical/infisical/k8-operator/packages/api" "github.com/Infisical/infisical/k8-operator/packages/constants" + "github.com/Infisical/infisical/k8-operator/packages/model" "github.com/Infisical/infisical/k8-operator/packages/util" "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" @@ -101,6 +105,48 @@ func (r *InfisicalPushSecretReconciler) updateResourceVariables(infisicalPushSec infisicalPushSecretResourceVariablesMap[string(infisicalPushSecret.UID)] = resourceVariables } +func (r *InfisicalPushSecretReconciler) processTemplatedSecrets(infisicalPushSecret v1alpha1.InfisicalPushSecret, kubePushSecret *corev1.Secret, destination v1alpha1.InfisicalPushSecretDestination) (map[string]string, error) { + + processedSecrets := make(map[string]string) + + sourceSecrets := make(map[string]model.SecretTemplateOptions) + for key, value := range kubePushSecret.Data { + + sourceSecrets[key] = model.SecretTemplateOptions{ + Value: string(value), + SecretPath: destination.SecretsPath, + } + } + + if infisicalPushSecret.Spec.Push.Secret.Template == nil || (infisicalPushSecret.Spec.Push.Secret.Template != nil && infisicalPushSecret.Spec.Push.Secret.Template.IncludeAllSecrets) { + for key, value := range kubePushSecret.Data { + processedSecrets[key] = string(value) + } + } + + if infisicalPushSecret.Spec.Push.Secret.Template != nil && + len(infisicalPushSecret.Spec.Push.Secret.Template.Data) > 0 { + + for templateKey, userTemplate := range infisicalPushSecret.Spec.Push.Secret.Template.Data { + + tmpl, err := template.New("push-secret-templates").Funcs(util.InfisicalSecretTemplateFunctions).Parse(userTemplate) + if err != nil { + return nil, fmt.Errorf("unable to compile template: %s [err=%v]", templateKey, err) + } + + buf := bytes.NewBuffer(nil) + err = tmpl.Execute(buf, sourceSecrets) + if err != nil { + return nil, fmt.Errorf("unable to execute template: %s [err=%v]", templateKey, err) + } + + processedSecrets[templateKey] = buf.String() + } + } + + return processedSecrets, nil +} + func (r *InfisicalPushSecretReconciler) ReconcileInfisicalPushSecret(ctx context.Context, logger logr.Logger, infisicalPushSecret v1alpha1.InfisicalPushSecret) error { resourceVariables := r.getResourceVariables(infisicalPushSecret) @@ -134,10 +180,9 @@ func (r *InfisicalPushSecretReconciler) ReconcileInfisicalPushSecret(ctx context return fmt.Errorf("unable to fetch kube secret [err=%s]", err) } - var kubeSecrets = make(map[string]string) - - for key, value := range kubePushSecret.Data { - kubeSecrets[key] = string(value) + processedSecrets, err := r.processTemplatedSecrets(infisicalPushSecret, kubePushSecret, infisicalPushSecret.Spec.Destination) + if err != nil { + return fmt.Errorf("unable to process templated secrets [err=%s]", err) } destination := infisicalPushSecret.Spec.Destination @@ -191,7 +236,7 @@ func (r *InfisicalPushSecretReconciler) ReconcileInfisicalPushSecret(ctx context infisicalPushSecret.Status.ManagedSecrets = make(map[string]string) // (string[id], string[key] ) - for secretKey, secretValue := range kubeSecrets { + for secretKey, secretValue := range processedSecrets { if exists := getExistingSecretByKey(secretKey); exists != nil { if updatePolicy == string(constants.PUSH_SECRET_REPLACE_POLICY_ENABLED) { @@ -280,7 +325,7 @@ func (r *InfisicalPushSecretReconciler) ReconcileInfisicalPushSecret(ctx context // We need to check if any of the secrets have been removed in the new kube secret for _, managedSecretKey := range infisicalPushSecret.Status.ManagedSecrets { - if _, ok := kubeSecrets[managedSecretKey]; !ok { + if _, ok := processedSecrets[managedSecretKey]; !ok { // Secret has been removed, verify that the secret is managed by the operator if getExistingSecretByKey(managedSecretKey) != nil { @@ -305,7 +350,7 @@ func (r *InfisicalPushSecretReconciler) ReconcileInfisicalPushSecret(ctx context } // We need to check if any new secrets have been added in the kube secret - for currentSecretKey := range kubeSecrets { + for currentSecretKey := range processedSecrets { if exists := getExistingSecretByKey(currentSecretKey); exists == nil { @@ -317,7 +362,7 @@ func (r *InfisicalPushSecretReconciler) ReconcileInfisicalPushSecret(ctx context createdSecret, err := infisicalClient.Secrets().Create(infisicalSdk.CreateSecretOptions{ SecretKey: currentSecretKey, - SecretValue: kubeSecrets[currentSecretKey], + SecretValue: processedSecrets[currentSecretKey], ProjectID: destination.ProjectID, Environment: destination.EnvironmentSlug, SecretPath: destination.SecretsPath, @@ -336,12 +381,12 @@ func (r *InfisicalPushSecretReconciler) ReconcileInfisicalPushSecret(ctx context existingSecret := getExistingSecretByKey(currentSecretKey) - if existingSecret != nil && existingSecret.SecretValue != kubeSecrets[currentSecretKey] { + if existingSecret != nil && existingSecret.SecretValue != processedSecrets[currentSecretKey] { logger.Info(fmt.Sprintf("Secret with key [key=%s] has changed value. Updating secret in Infisical", currentSecretKey)) updatedSecret, err := infisicalClient.Secrets().Update(infisicalSdk.UpdateSecretOptions{ SecretKey: currentSecretKey, - NewSecretValue: kubeSecrets[currentSecretKey], + NewSecretValue: processedSecrets[currentSecretKey], ProjectID: destination.ProjectID, Environment: destination.EnvironmentSlug, SecretPath: destination.SecretsPath, @@ -353,7 +398,7 @@ func (r *InfisicalPushSecretReconciler) ReconcileInfisicalPushSecret(ctx context continue } - updateExistingSecretByKey(currentSecretKey, kubeSecrets[currentSecretKey]) + updateExistingSecretByKey(currentSecretKey, processedSecrets[currentSecretKey]) infisicalPushSecret.Status.ManagedSecrets[updatedSecret.ID] = currentSecretKey } } @@ -361,7 +406,7 @@ func (r *InfisicalPushSecretReconciler) ReconcileInfisicalPushSecret(ctx context } // Check if any of the existing secrets values have changed - for secretKey, secretValue := range kubeSecrets { + for secretKey, secretValue := range processedSecrets { existingSecret := getExistingSecretByKey(secretKey) diff --git a/k8-operator/controllers/infisicalsecret/infisicalsecret_helper.go b/k8-operator/controllers/infisicalsecret/infisicalsecret_helper.go index eb41fe6e9..54afbfa90 100644 --- a/k8-operator/controllers/infisicalsecret/infisicalsecret_helper.go +++ b/k8-operator/controllers/infisicalsecret/infisicalsecret_helper.go @@ -3,7 +3,6 @@ package controllers import ( "bytes" "context" - "encoding/base64" "errors" "fmt" "strings" @@ -156,16 +155,6 @@ func (r *InfisicalSecretReconciler) getInfisicalServiceAccountCredentialsFromKub return model.ServiceAccountDetails{AccessKey: string(accessKeyFromSecret), PrivateKey: string(privateKeyFromSecret), PublicKey: string(publicKeyFromSecret)}, nil } -var infisicalSecretTemplateFunctions = template.FuncMap{ - "decodeBase64ToBytes": func(encodedString string) string { - decoded, err := base64.StdEncoding.DecodeString(encodedString) - if err != nil { - panic(fmt.Sprintf("Error: %v", err)) - } - return string(decoded) - }, -} - func convertBinaryToStringMap(binaryMap map[string][]byte) map[string]string { stringMap := make(map[string]string) for k, v := range binaryMap { @@ -177,7 +166,7 @@ func convertBinaryToStringMap(binaryMap map[string][]byte) map[string]string { func (r *InfisicalSecretReconciler) createInfisicalManagedKubeResource(ctx context.Context, logger logr.Logger, infisicalSecret v1alpha1.InfisicalSecret, managedSecretReferenceInterface interface{}, secretsFromAPI []model.SingleEnvironmentVariable, ETag string, resourceType constants.ManagedKubeResourceType) error { plainProcessedSecrets := make(map[string][]byte) - var managedTemplateData *v1alpha1.InfisicalSecretTemplate + var managedTemplateData *v1alpha1.SecretTemplate if resourceType == constants.MANAGED_KUBE_RESOURCE_TYPE_SECRET { managedTemplateData = managedSecretReferenceInterface.(v1alpha1.ManagedKubeSecretConfig).Template @@ -201,7 +190,7 @@ func (r *InfisicalSecretReconciler) createInfisicalManagedKubeResource(ctx conte } for templateKey, userTemplate := range managedTemplateData.Data { - tmpl, err := template.New("secret-templates").Funcs(infisicalSecretTemplateFunctions).Parse(userTemplate) + tmpl, err := template.New("secret-templates").Funcs(util.InfisicalSecretTemplateFunctions).Parse(userTemplate) if err != nil { return fmt.Errorf("unable to compile template: %s [err=%v]", templateKey, err) } @@ -322,7 +311,7 @@ func (r *InfisicalSecretReconciler) updateInfisicalManagedKubeSecret(ctx context } for templateKey, userTemplate := range managedTemplateData.Data { - tmpl, err := template.New("secret-templates").Funcs(infisicalSecretTemplateFunctions).Parse(userTemplate) + tmpl, err := template.New("secret-templates").Funcs(util.InfisicalSecretTemplateFunctions).Parse(userTemplate) if err != nil { return fmt.Errorf("unable to compile template: %s [err=%v]", templateKey, err) } @@ -373,7 +362,7 @@ func (r *InfisicalSecretReconciler) updateInfisicalManagedConfigMap(ctx context. } for templateKey, userTemplate := range managedTemplateData.Data { - tmpl, err := template.New("secret-templates").Funcs(infisicalSecretTemplateFunctions).Parse(userTemplate) + tmpl, err := template.New("secret-templates").Funcs(util.InfisicalSecretTemplateFunctions).Parse(userTemplate) if err != nil { return fmt.Errorf("unable to compile template: %s [err=%v]", templateKey, err) } diff --git a/k8-operator/packages/util/template.go b/k8-operator/packages/util/template.go new file mode 100644 index 000000000..c8ed98e48 --- /dev/null +++ b/k8-operator/packages/util/template.go @@ -0,0 +1,20 @@ +package util + +import ( + "encoding/base64" + "fmt" + "text/template" +) + +var InfisicalSecretTemplateFunctions = template.FuncMap{ + "decodeBase64ToBytes": func(encodedString string) string { + decoded, err := base64.StdEncoding.DecodeString(encodedString) + if err != nil { + panic(fmt.Sprintf("Error: %v", err)) + } + return string(decoded) + }, + "encodeBase64": func(plainString string) string { + return base64.StdEncoding.EncodeToString([]byte(plainString)) + }, +}