Sign in
← Kubernetes: Kustomize and Helm
5 min · easy · Lesson 6 of 9

Kustomize: Secret generator

secretGenerator, and an honest look at how base64 in a Secret protects nothing.

Why

A database password, an API token, a certificate's private key: none of these belong in a ConfigMap next to a button color. Kubernetes has a separate object for them, and Kustomize builds it the same way it built the ConfigMap in the last lesson.

Secret is the Kubernetes object for sensitive data: passwords, tokens, keys, and certificates. It works almost like ConfigMap. It differs in object type, in having separate access rules, and in storing values in the data field encoded as base64.

secretGenerator follows the same rules as configMapGenerator: the same three sources (literals, files, envs), the same hash suffix, the same generatorOptions block.

Generating from literals

secretGenerator:
  - name: app-secret
    literals:
      - DB_PASSWORD=s3cr3t
      - API_TOKEN=abc123

Write values as plain text. You don't encode them in base64 by hand: Kustomize does that at render time. Encode them ahead of time and Kustomize will encode the already-encoded string again. The result is a Secret of type Opaque:

apiVersion: v1
data:
  API_TOKEN: YWJjMTIz
  DB_PASSWORD: czNjcjN0
kind: Secret
metadata:
  name: app-secret-ddg88mbgh9
type: Opaque

Secret from files

For certificates and keys, files is more convenient: a PEM file is multi-line, and you can't paste it into literals.

secretGenerator:
  - name: web-tls
    type: kubernetes.io/tls
    files:
      - tls.crt=certs/site.pem
      - tls.key=certs/site.key

The type field sets the Secret's type. Without it you get a plain Opaque. The kubernetes.io/tls type requires the keys tls.crt and tls.key, and by default the key becomes the file name. That's why files get renamed on the way in: to the left of = is the key name, to the right is the file path.

Kustomize doesn't check type requirements. A Secret with keys site.pem and site.key will build without a single error, and only the API server will reject it, at kubectl apply.

There's also envs: it parses a KEY=value file line by line, and each line becomes a separate key. Useful when a set of variables already lives in an .env file:

secretGenerator:
  - name: app-env
    envs:
      - secret.env

files with that same secret.env would give you one key, secret.env, holding the entire file.

With files, the file lands in the Secret exactly as it is, trailing newline included. A password written to a file with echo arrives one character longer and won't match. echo -n or printf fixes it.

base64 is encoding, not encryption

Values in a Secret look like random text, and it's easy to mistake that for protection. There isn't any. base64 is a reversible encoding, built for passing binary data as text. Anyone with permission to read the Secret gets the original value back with one command:

kubectl get secret app-secret-ddg88mbgh9 -o jsonpath='{.data.DB_PASSWORD}' | base64 --decode
s3cr3t

base64 --decode works the same on macOS and Linux. The same trick works without a cluster too, on the output of kubectl kustomize.

What actually limits access:

The practical value of Secret is that it separates sensitive data from the rest of the configuration and gives it its own access-control point. The object itself doesn't encrypt the content.

For the same reason, kubectl kustomize . prints the finished Secret straight to the terminal. In CI, that output ends up in the pipeline logs, where anyone with access to the builds can read it.

The hash suffix

Just like ConfigMap, a content hash gets appended to the name: app-secret-ddg88mbgh9. Change the value, and the name changes too. Kustomize fixes up the reference in the Deployment, the Pod template becomes different, and the cluster starts a rollout: Pods get recreated and pick up the new password.

Turn it off the same way:

generatorOptions:
  disableNameSuffixHash: true

Without the hash, the Secret's name is fixed. After you change the password, kubectl apply -k updates the data in the Secret, but the Pod template in the Deployment doesn't change, no rollout starts, and the running Pods keep the old environment variables until you restart them by hand.

What usually breaks

A password in literals lands in git in plain text. That's the main problem with secretGenerator, and Kustomize doesn't solve it. Repositories keep either encrypted files (SOPS, sealed-secrets) or just a reference to an external store, and leave literals for local experiments.

Don't render for debugging on a step whose logs are publicly readable.

A manual manifest and a generator with the same name. If resources still has secret.yaml with a Secret app-secret, and there's a generator named app-secret right next to it, the build fails:

error: merging from generator &{...}: id resid.ResId{Gvk:resid.Gvk{Group:"", Version:"v1", Kind:"Secret", isClusterScoped:false}, Name:"app-secret", Namespace:""} exists; can not use behavior: 'unspecified', behavior must be merge or replace

Moving a Secret to the generator? Remove the manual file from resources.

Changing a Secret's type on a live object doesn't work: the type field is immutable. If a Secret was created as Opaque and you later decide to make it kubernetes.io/tls, you'll have to delete the object and create it again. With the hash suffix enabled, this usually isn't a problem: the new type changes the hash, and an object with a different name gets created.

What you'll need for the tasks

Homework

Practice the theory on your own cluster: 2 steps with a check. Set up the cluster with the Kubernetes locally track, the tasks live in the k8s-practice repository.

./run.sh start k8s-kustomize-secret-generator     # set up the starting state
./run.sh verify k8s-kustomize-secret-generator    # check the current step

In short

Done reading?

Mark the lesson as read to move your track progress forward.

Go through it with an AI agent

The agent explains anything unclear in plain words, gives you 2 labs for this lesson and drills you on interview questions. $49 one-time, lifetime access.

Get access for $49

Tell the agent: use MCP izi, give me lesson k8s-packaging-06-kustomize-secret-generator