skip to content

What does b64enc in a Helm chart's Secret template protect, and what does it not?

level: juniorimportance: must knowfreq 74%

answer

  1. Ask what the function is for
  2. The Secret API field demands a format
  3. There is an inverse function
  4. stringData produces the same object
  5. Count the copies of the plaintext

basics

~20 s

Nothing confidential. b64enc is base64 encoding, needed only because a Kubernetes Secret's data field must hold base64 text. It is reversible by anyone, and the same plaintext still sits in the values file and in the stored release record.

solid answer

~50 s

`b64enc` is sprig's base64 encoder, and Helm charts use it because a Kubernetes Secret's `data` map is defined as base64 text — not because it protects anything. It has no key and `b64dec` reverses it in one pipeline stage. The proof that it adds nothing is that a chart can write the same value into `stringData` in plaintext and get an identical stored object. Worse, the template line is the *last* copy of the credential, not the only one: the value also lives in whatever values file or `--set` supplied it, in the shell or job that ran the command, and in the release record Secret Helm writes for the revision, which holds both the supplied values and the rendered manifest. Protection has to come from keeping the material out of `.Values` entirely, not from an encoding function.

code

yaml · 15 lines
yaml
apiVersion: v1
kind: Secret
metadata:
  name: pdfsign-signing
type: Opaque
data:
  passphrase: {{ .Values.signing.passphrase | b64enc | quote }}
---
apiVersion: v1
kind: Secret
metadata:
  name: pdfsign-signing-alt
type: Opaque
stringData:
  passphrase: {{ .Values.signing.passphrase | quote }}

go deeper

for a junior

Recall that base64 is an encoding, not encryption, and that a Kubernetes Secret's data field requires it. Be able to say out loud that anyone can decode the value and that a password in values.yaml is a password in Git.

for a middle

Explain why the function is needed at all — the data field's format — and that writing to stringData produces the identical object. Be ready to list the other places the same plaintext lives once helm install has run.

for a senior

Show that you treat the rendered Secret as the last and least interesting copy. Talk about keeping credentials out of .Values altogether, and about rendered output and release records being just as readable as the values file.

for a principal

Own the rule your organisation enforces: whether a chart may accept credential material through values at all, what a reviewer is expected to reject, and how you would find the charts that already do it across an estate.

### What `b64enc` actually is Helm renders every file under `templates/` with Go's `text/template` plus the sprig function library, and `b64enc` is sprig's **base64 encoder**. It takes a string and returns the same bytes written in the 64-character alphabet. Its inverse, `b64dec`, is available in the very same template dialect, in `kubectl`, in every language runtime and in three lines of any browser console. Base64 is a *transport encoding* — a way to put arbitrary bytes into a field that only accepts printable ASCII. It is not a cipher, it has no key, and it hides nothing from anyone. The reason it shows up in almost every chart that renders a Secret is mechanical: a Kubernetes Secret's `data` map is defined as base64-encoded values, so a chart that writes into `data` must encode. That is the whole story: ```yaml apiVersion: v1 kind: Secret metadata: name: pdfsign-signing type: Opaque data: passphrase: {{ .Values.signing.passphrase | b64enc | quote }} ``` Written this way, `b64enc` is satisfying an API field's format requirement, exactly like `quote` satisfies YAML's need for a quoted string. A chart author who wants to skip the encoding entirely can write into `stringData` instead, which accepts plaintext and is encoded by the API server on write — the stored object is identical either way. That the two spellings are interchangeable is the cleanest proof that `b64enc` adds no protection: if it did, dropping it could not produce the same result. ### Where the plaintext actually is The more useful half of the answer is the trail of copies that exist around that one template line. A passphrase for a PDF-signing service that arrives through `.Values` typically exists in at least four places at once: 1. **In the chart or a values file.** If the default lives in `values.yaml`, it is in the chart tarball and in the chart's Git history. If it arrives through `-f prod-values.yaml`, it is in whatever repository that file lives in — and Git history is append-only, so deleting the line later does not remove it. 2. **In the invocation.** `--set signing.passphrase=...` puts it in the shell history of the machine that ran it, and in the job log of whatever ran that command. 3. **In the release record.** Helm stores each revision as a Secret named `sh.helm.release.v1.<release>.v<revision>` in the release namespace. That record contains the values the caller supplied *and* the rendered manifest, so the passphrase is in it twice. `helm get values` and `helm get manifest` read it straight back out. 4. **In the live Secret object** the chart rendered. `b64enc` is applied at step 4 only, and even there it is reversed by the first person who looks. Nothing about it touches steps 1 through 3. ### What does protect the value Real protection comes from somewhere other than the chart's template functions. Inside Helm's own surface, the lever is *not putting the material through `.Values` at all* — having the chart accept the **name** of a Secret that something else created, so the credential never enters the values, never enters the release record and never appears in `helm template` output. Outside Helm's surface, who may read Secret objects in a namespace, and how the cluster stores them, are Kubernetes concerns rather than chart concerns; note only that they cover the live object and do nothing about the values file sitting in a repository. ### The specific mistakes this question is screening for Candidates who have only consumed charts often describe `b64enc` as "encoding it so it is not in plaintext", which is a contradiction — encoded *is* plaintext, in a costume. A second common error is believing that `helm template` is safe to paste into a ticket or a CI log because the Secret's value "looks like a hash". It is not a hash; it round-trips. A third, subtler one: `b64enc` and `quote` are sometimes applied in the wrong order or one is omitted. `{{ .Values.x | quote | b64enc }}` encodes the quotation marks *into* the secret, so the consuming application receives a value wrapped in literal `"` characters — a real bug that surfaces as an authentication failure with no obvious cause. The correct order encodes first and quotes the encoded result, as in the snippet above. Multi-line material such as a private key is usually pulled in with `--set-file` or read from the chart with `.Files.Get` and then piped through `b64enc`, which handles newlines correctly where hand-editing a YAML block scalar frequently does not. Finally: base64's one genuine operational property is that it makes the value *survive* — through YAML, through JSON, through shells — without being mangled. Treat it as plumbing. If a reviewer sees `b64enc` and concludes the chart handles secrets, the review has already failed.

  • If b64enc protects nothing, why not always use stringData and drop it?
    You can, and for a single-line credential it is clearer. `b64enc` stays necessary for material that is already binary or that arrives as a file — a signing key pulled in with `--set-file` or read from the chart with `.Files.Get` — because encoding it avoids the YAML block-scalar indentation traps that hand-written multi-line values fall into. Both forms end up as the same object; the choice is about template readability, not security.
  • A chart writes {{ .Values.passphrase | quote | b64enc }}. What breaks?
    The quotation marks get encoded into the secret. The consuming process decodes the value and receives it wrapped in literal double quotes, so authentication fails with a credential that looks correct in every log. Encode first, then quote the encoded result: `| b64enc | quote`.
  • Is helm template output safe to paste into a ticket if the Secret values look scrambled?
    No. Those values are base64, not a hash, and anyone can decode them. Rendered output should be treated as carrying the same plaintext the values did — which is also why rendering a chart with real production values inside a shared pipeline log is a leak, regardless of what the Secret template does.

saying these in an interview costs you the question

  • Calling base64 encryption, or saying the value is hashed
  • Believing b64enc makes it safe to commit a password to values.yaml
  • Thinking helm template output hides Secret values
  • Not knowing b64dec reverses it with no key
  • Assuming the encoded value is the only copy of the credential
  • Writing quote before b64enc and encoding the quotation marks

context