This has tripped me up a lot, so I figure it is worth a quick note.
The Problem
I use Helm charts to define the state of my cluster in a Git repository, and ArgoCD to deploy those charts. This allows a lot of flexibility in my deployments and configuration.
For secrets management, I use External Secrets to populate secrets from Hashicorp Vault. In many of those cases, I need to use the templating functionality of External Secrets to build secrets that can be used from external charts. A great case of this is populating user secrets for the RabbitMQ chart.
In the link above, you will notice the templates/default-user-secrets.yaml
file. This file is meant to generate a Kubernetes Secret
resource which is then sent to the RabbitMqCluster
resource (templates/cluster.yaml
). This secret is mounted as a file, and therefore, needs some custom formatting. So I used the template
property to format the secret:
template:
type: Opaque
engineVersion: v2
data:
default_user.conf: |
default_user={{ `{{ .username }}` }}
default_pass={{ `{{ .password }}` }}
host: {{ .Release.Name }}.rabbitmq.svc
password: {{`"{{ .password }}"`}}
port: "5672"
provider: rabbitmq
type: rabbitmq
username: {{`"{{ .username }}"`}}
Notice in the code above the duplicated {{
and }}
around the username/password values. These are necessary to ensure that the template is properly set in the ExternalSecret
resource.
But, Why?
It has to do with templating. Helm uses golang
templates to process the templates and create resources. Similarly, the ExternalSecrets template engine uses golang
templates. When you have a “template in a template”, you have to somehow tell the processor to put the literal value in.
Let’s look at one part of this file.
default_user={{ `{{ .username }}` }}
What we want to end up in the ExternalSecret
template is this:
default_user={{ .username }}
So, in order to do that, we have to tell the Helm template to write {{ .username }}
as written, not processing it as a golang
template. In this case, we use the backtick (`) to allow for this escape without having that value written to the template. Notice that other areas use the double-quote (“) to wrap the template.
password: {{`"{{ .password }}"`}}
This will generate the quotes in the resulting template:
password: "{{ .password }}"
If you need a single quote, the use the same pattern, but replace the double quote with a single quote (‘).
username: {{`'{{ .username }}'`}}
For whatever it is worth, VS Code’s YAML parser did not like that version at all. Since I have not run into a situation where I need a single quote, I use double quotes if quotes are required, and backticks if they are not.