Vault 'agent-inject-template' annotation throwing error - kubernetes-helm

I want to update my existing vault 'agent-inject-template' annotation to support the 'export' option as mentioned in the official doc.
Kubernetes version - 1.21
Current working template
{{- range $value := $.Values.vault.secrets }}
{{- $secretName := regexFind "[^/]+$" $value }}
vault.hashicorp.com/agent-inject-secret-{{ $secretName }}: {{ $value | quote }}
vault.hashicorp.com/agent-inject-template-{{ $secretName }}: |
{{`{{- with secret `}}{{ $value | quote }}{{` -}}
{{ .Data.data | toJSON }}
{{- end }}`}}
{{- end }}
Current value.yaml
vault:
enabled: true
secrets:
- path/to/secret/database
Results in /vault/secrets/database
{"host":"example.us-east-1.rds.amazonaws.com","port":5432,"user":"postgres"}
What I have tried
helm template
{{- range $value := $.Values.vault.secrets }}
{{- $secretName := regexFind "[^/]+$" .path }}
vault.hashicorp.com/agent-inject-template-{{ $secretName }}: |
{{`{{- with secret `}}{{ .path | quote }}{{` -}}
{{ .Data.data | toJSON }}
{{- if .exports }}
{{- range $key, $value := .exports }}
export {{ $key }}={{ .Data.data.$value }}
{{- end }}
{{- end }}
{{- end }}`}}
values file
vault:
enabled: false
secrets:
- path: path/to/secret/database
exports:
DB_HOST: host
DB_PORT: port
- path: path/to/secret/redis
exports:
REDIS_HOST: host
REDIS_PORT: port
The error I am getting
│ vault-agent-init [INFO] (runner) starting │
│ vault-agent-init [ERROR] template.server: template server error: error="(dynamic): parse: template: :5: bad character U+0024 '$'" │
│ vault-agent-init [INFO] (runner) stopping │
│ vault-agent-init [INFO] template.server: template server stopped │
│ vault-agent-init [INFO] auth.handler: shutdown triggered, stopping lifetime watcher │
│ vault-agent-init [INFO] auth.handler: auth handler stopped │
│ vault-agent-init [ERROR] runtime error encountered: error="template server: (dynamic): parse: template: :5: bad character U+0024 '$'" │
│ vault-agent-init Error encountered during run, refer to logs for more details. │
│ Stream closed EOF for service-example/example-generic-internal-xxx-xxx (vault-agent-init)

I have a simplified example on how I handle it. Maybe that will help you. Basically, I just put {{ $value }} in single quotes, therefore special characters are being parsed as text.
vault.hashicorp.com/agent-inject-secret-x: dev/secrets/data/path/x
vault.hashicorp.com/agent-inject-template-x: |
{{- with secret "dev/secrets/data/path/x" -}}
{{- range $key, $value := .Data.data }}
export {{ $key }}='{{ $value }}'
{{- end }}
{{- end -}}
In your case, error message shows it cannot parse '$', which you don't have in your secret, what tells that the issue is in your config.

Related

Helm get value from secret

I was wondering if there is any workaround to set a value in a secret and let helm render it before install. The use case is this, I'm using the bitnami chart for rabbitmq and I want to add SSO with my azure active directory, there is the variable advancedConfiguration: |- ... for that purpose but I have to put the configuration in plain text and add it to version control. As you can imagine, I don't want to do that.
The SSO config is like the following json:
advancedConfiguration: |-
[
{rabbit, [
{auth_backends, [rabbit_auth_backend_oauth2, rabbit_auth_backend_internal]}
]},
{rabbitmq_auth_backend_oauth2, [
{resource_server_id, <<"CLIENT_ID">>},
{extra_scopes_source, <<"roles">>},
{key_config, [
{jwks_url, <<"https://login.microsoftonline.com/PROVIDER_ID/discovery/v2.0/keys">>}
]}
]},
{rabbitmq_management, [
{oauth_enabled, true},
{oauth_client_id, "CLIEND_ID"},
{oauth_client_secret, "CLIENT_SECRET"},
{oauth_provider_url, "https://login.microsoftonline.com/PROVIDER_ID"}
]}
].
The PROVIDER_ID, CLIEND_ID and CLIENT_SECRET are the values that I want to hide.
I have read about helm --post-renderer flag, but I am using argocd for deploys and it seems that it is not compatible with that flag.
What options do I have to solve this correctly? Thanks in advance.
This is what the chart does with the value:
apiVersion: v1
kind: Secret
metadata:
name: {{ printf "%s-config" (include "common.names.fullname" .) }}
namespace: {{ include "common.names.namespace" . | quote }}
labels: {{- include "common.labels.standard" . | nindent 4 }}
{{- if .Values.commonLabels }}
{{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }}
{{- end }}
{{- if .Values.commonAnnotations }}
annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
{{- end }}
type: Opaque
data:
rabbitmq.conf: |-
{{- include "common.tplvalues.render" (dict "value" .Values.configuration "context" $) | b64enc | nindent 4 }}
{{- if .Values.advancedConfiguration }}
advanced.config: |-
{{- include "common.tplvalues.render" (dict "value" .Values.advancedConfiguration "context" $) | b64enc | nindent 4 }}
{{- end }}
As I said, I update the chart and submit a PR. This is solved in the version 11.3.0 using the key advancedConfigurationExistingSecret instead of the previous key.
If you are curious about this here are the details:
Docs: https://artifacthub.io/packages/helm/bitnami/rabbitmq/11.3.0
PR: https://github.com/bitnami/charts/pull/14071

Nested ranges from directorys in helm

Having to generate templates based on the existence of certain files in the tree.
the best i find to do this is with multiple ranges in the helm file and some ifs to check but it seams that helm does not like this kind of nesting.
Chart tree
├── ms-values
│ ├── shared
│ │ ├── ms1.yml
│ │ └── ms2.yml
│ └── devops
│ ├── test
│ │ └── ms3.yml
│ ├── ms3.yml
│ └── ms4.yml
├── family-values
│ ├── test
│ │ └── shared.yml
│ ├── devops.yml
│ └── shared.yml
├── global-values
│ ├── test.yml
│ └── dev.yml
├── templates
│ └── micoservices.yml
└── values.yml
i have a file microservices.yml in the templates with this content:
{{ $enviroment := trimSuffix ".yml" (base $globalPath) }}
enviroment: {{ $enviroment }}
{{- range $familyPath, $familyBytes := $.Files.Glob "family-values/*.yml" -}}
{{ $family := trimSuffix ".yml" (base $familyPath) }}
{{- $familyMsPath := print "ms-values/" $family "/*.yml" }}
{{- range $microservicePath, $microserviceBytes := $.Files.Glob $familyMsPath -}}
{{- $microservice := trimSuffix ".yml" (base $microservicePath) -}}
{{- $microserviceExt := base $microservicePath -}}
{{- $envMSPath := print "ms-values/" $family "/" $enviroment "/" $microserviceExt -}}
{{- $microserviceEnv := $.Files.Glob $envMSPath }}
familys: {{ $family }}
enviroment: {{ $enviroment }}
MS: {{ $microservice -}}
{{- if $microserviceEnv }}
MS_PATCH: {{- $envMSPath -}}
{{- end -}}
{{- $FamilyENVPath := print "family-values/" $enviroment "/" $family ".yml" -}}
{{- $FamilyENV := $.Files.Glob $FamilyENVPath }}
{{- if $FamilyENV }}
familyENVpatch: {{ $FamilyENVPath }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}
Runing helm template . --debug i I have the chart rendered but also this error:
helm.go:81: [debug] error converting YAML to JSON: yaml: line 2: mapping values are not allowed in this context
YAML parse error on argo-apps/templates/microservices.yml
helm.sh/helm/v3/pkg/releaseutil.(*manifestFile).sort
/home/circleci/helm.sh/helm/pkg/releaseutil/manifest_sorter.go:146
helm.sh/helm/v3/pkg/releaseutil.SortManifests
/home/circleci/helm.sh/helm/pkg/releaseutil/manifest_sorter.go:106
helm.sh/helm/v3/pkg/action.(*Configuration).renderResources
/home/circleci/helm.sh/helm/pkg/action/action.go:165
helm.sh/helm/v3/pkg/action.(*Install).Run
/home/circleci/helm.sh/helm/pkg/action/install.go:239
main.runInstall
/home/circleci/helm.sh/helm/cmd/helm/install.go:241
main.newTemplateCmd.func2
/home/circleci/helm.sh/helm/cmd/helm/template.go:70
github.com/spf13/cobra.(*Command).execute
/go/pkg/mod/github.com/spf13/cobra#v1.0.0/command.go:842
github.com/spf13/cobra.(*Command).ExecuteC
/go/pkg/mod/github.com/spf13/cobra#v1.0.0/command.go:950
github.com/spf13/cobra.(*Command).Execute
/go/pkg/mod/github.com/spf13/cobra#v1.0.0/command.go:887
main.main
/home/circleci/helm.sh/helm/cmd/helm/helm.go:80
runtime.main
/usr/local/go/src/runtime/proc.go:203
runtime.goexit
/usr/local/go/src/runtime/asm_amd64.s:1373```
Any ideas??
the issue (i think) to the indentation of the helm file. i solved here is the code
{{- $enviroment := trimSuffix ".yml" (base $globalPath) }}
{{ range $familyPath, $familyBytes := $.Files.Glob "family-values/*.yml" }}
{{ $family := trimSuffix ".yml" (base $familyPath) -}}
{{ $familyMsPath := print "ms-values/" $family "/*.yml" }}
{{ range $microservicePath, $microserviceBytes := $.Files.Glob $familyMsPath }}
{{ $microservice := trimSuffix ".yml" (base $microservicePath) -}}
{{ $envMSPath := print "ms-values/" $family "/" $enviroment "/" $microservice ".yml" }}
{{ $microserviceEnv := $.Files.Glob $envMSPath }}
{{ $microserviceData := $.Files.Get $microservicePath | fromYaml}}
{{ if has $enviroment $microserviceData.enviromentEnabled }}
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: {{ $family }}-{{ $microservice }}
namespace: argos
spec:
project: {{ $enviroment }}-{{ $family }}-{{ $microservice }}
source:
path: microservice
repoURL: 'git#example:infra/devops-charts.git'
targetRevision: HEAD
helm:
valueFiles:
- global-values/{{ $enviroment }}.yml
- family-values/{{ $family }}.yml
{{- $FamilyENVPath := print "family-values/" $enviroment "/" $family ".yml" }}
{{- $FamilyENV := $.Files.Glob $FamilyENVPath }}
{{- if $FamilyENV }}
- {{ $FamilyENVPath }}
{{- end }}
- ms-values/{{ $microservice }}.yml
{{- if $microserviceEnv }}
- {{ $envMSPath }}
{{- end }}
{{- range $key, $value := $.Values.clusters -}}
{{- if eq $key $enviroment }}
destination:
server: {{ $value }}
namespace: "{{ $family }}-{{ $microservice }}"
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}

significance of .Values.nameOverride while declaring cassandra.name in helper template

I was reviewing helm template on git repo https://github.com/helm/charts/tree/master/incubator/cassandra
for deploying cassandra in Kubernetes.
I can see in helper template file "_helpers.tpl" , "cassandra.name" has been defined as below , as I can understand whose default value set to name of the Chart , but why .Values.nameOverride used here , without any pipe (just after .Chart.Name) , what is the significant of the same ,I am confused here .
{{- define "cassandra.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
which is used in cassandra/template/configmap.yaml as below
{{- if .Values.configOverrides }}
kind: ConfigMap
apiVersion: v1
metadata:
name: {{ template "cassandra.name" . }}
namespace: {{ .Release.Namespace }}
labels:
app: {{ template "cassandra.name" . }}
chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
data:
{{ toYaml .Values.configOverrides | indent 2 }}
{{- end }}
Sprig default function takes two parameters, that's why there is no pipe.
If .Values.nameOverride is empty, .Chart.Name will be used.

helm range get values outside of loop

I was looking at the helm range example they have on their docs.
yaml
favorite:
drink: coffee
food: pizza
pizzaToppings:
- mushrooms
- cheese
- peppers
- onions
helm
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
{{- end }}
toppings: |-
{{- range .Values.pizzaToppings }}
- {{ . | title | quote }}
- {{ .Values.favorite.drink }}
{{- end }}
I updated it to have this line - {{ .Values.favorite.drink }} but when I run helm template I get the error
can't evaluate field Values
Is there anyway to access the top level .Values from within the range function and escape the loop?
You can also use a global variable $ that points to the root context
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
{{- end }}
toppings: |-
{{- range $.Values.pizzaToppings }}
- {{ . | title | quote }}
- {{ $.Values.favorite.drink }}
{{- end }}
You can use a variable:
toppings: |-
{{- $drink := .Values.favorite.drink }}
{{- range .Values.pizzaToppings }}
- {{ . | title | quote }}
- {{ $drink }}
{{- end }}
You can assign Values to a variable as well if you prefer.
toppings: |-
{{- $val := .Values }}
{{- range .Values.pizzaToppings }}
- {{ . | title | quote }}
- {{ $val.favorite.drink }}
{{- end }}

Check if files/dirs/ used in templates exists

Given the following json:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "something.server.fullname" . }}
data:
{{ (.Files.Glob "dashboards/*.json").AsConfig | indent 2 }}
{{ (.Files.Glob "datasources/*.json").AsConfig | indent 2 }}
How can I check if the folder exists and is not empty?
Currently, if the folder is missing or doesn't have any files, helm install will abort with this message:
Error: YAML parse error on domething/charts/grafana/templates/dashboards-configmap.yaml: error converting YAML to JSON: yaml: line 6821: could not find expected ':'
You can pull your Globs out to variables, and then move everything within if blocks, e.g.:
{{- $globdash := .Files.Glob "dashboards/*.json" }}
{{ if $globdash }}
{{- $globdata := .Files.Glob "datasources/*.json" }}
{{ if $globdata }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "something.server.fullname" . }}
data:
{{ ($globdash).AsConfig | indent 2 }}
{{ ($globdata).AsConfig | indent 2 }}
{{ end }}
{{ end }}