Kubernetes Secrets — Commands Reference¶
Reference: https://kubernetes.io/docs/concepts/configuration/secret/
See also:
secret_1.md.mdfor Secret structure, types, base64 encoding, pod usage, and exam docs strategy.
--from-file vs --from-literal — The Key Difference¶
The raw notes question was: "The question says using the contents of the file — use --from-file, not --from-literal."
Here's why they're different:
--from-literal¶
You define the key name AND the value directly on the command line. The key is mykey, the value is mysecretvalue. The file system is not involved at all.
--from-file¶
The filename becomes the key, the file contents become the value. So if database-data.txt contains the text s3cr3tpassword, the secret will have:
- Key: database-data.txt
- Value: s3cr3tpassword (base64-encoded behind the scenes)
Override the key name:
Now the key is mykey instead of the filename. Use this when the question says "the key should be called X."
Multiple files:
kubectl create secret generic tls-secret \
--from-file=tls.crt=./server.crt \
--from-file=tls.key=./server.key
Each file becomes one key in the secret.
When to use which¶
| Task description | Command |
|---|---|
| "Create a secret with key=value" | --from-literal=key=value |
| "Create a secret using the contents of this file" | --from-file=file.txt |
| "Create a secret from this file, key should be called X" | --from-file=X=file.txt |
The exam will often say "using the contents of the file" as a hint — that's --from-file.
Creating Secrets — All Methods¶
Generic (Opaque)¶
# From literals
kubectl create secret generic db-secret \
--from-literal=username=admin \
--from-literal=password=s3cr3t
# From a file (filename = key)
kubectl create secret generic db-secret \
--from-file=credentials.txt
# From a file with custom key name
kubectl create secret generic db-secret \
--from-file=mykey=credentials.txt
# From a .env file (KEY=VALUE per line, each line = one key in the secret)
kubectl create secret generic db-secret \
--from-env-file=.env
--from-env-file vs --from-file:
- --from-file=.env → one key in the secret, key is .env, value is the entire file contents
- --from-env-file=.env → parses the file line by line (KEY=VALUE), each line becomes a separate key in the secret
TLS Secret¶
Creates a kubernetes.io/tls type secret with exactly two keys: tls.crt and tls.key. Used with Ingress TLS.
Docker Registry Secret¶
kubectl create secret docker-registry my-registry-secret \
--docker-server=registry.example.com \
--docker-username=myuser \
--docker-password=mypassword \
--docker-email=email@example.com
Creates a kubernetes.io/dockerconfigjson type secret. Used with imagePullSecrets so pods can pull from private registries.
Generate YAML without creating (dry-run)¶
Prints the YAML to stdout. Pipe to a file or kubectl apply -f -:
kubectl create secret generic db-secret \
--from-literal=password=s3cr3t \
--dry-run=client -o yaml > secret.yaml
kubectl apply -f secret.yaml
Reading / Inspecting Secrets¶
List all secrets in a namespace¶
kubectl get secrets # current namespace
kubectl get secrets -n kube-system # specific namespace
kubectl get secrets -A # all namespaces
describe — shows metadata and keys, NOT values¶
Output:
describe intentionally hides values. It shows key names and their sizes only. Useful to confirm the secret exists and what keys it has.
get -o yaml — shows everything including base64-encoded values¶
Output:
apiVersion: v1
kind: Secret
metadata:
name: db-secret
namespace: default
type: Opaque
data:
password: czNjcjN0
username: YWRtaW4=
Values are base64-encoded. You still need to decode them to see the actual values.
Extract and decode a specific key — two-step approach¶
# Step 1: see what keys exist
kubectl get secret db-secret -o jsonpath='{.data}'
# Step 2: extract and decode the key you want
kubectl get secret db-secret -o jsonpath='{.data.password}' | base64 -d
One-liner (no intermediate step):
Write to a file:
Manually encode / decode base64¶
echo -n "mysecretvalue" | base64 # encode — outputs base64 string
echo "czNjcjN0" | base64 -d # decode — outputs plain text
Critical: the -n flag on echo
echo "hello" | base64 # encodes "hello\n" — includes the newline character
echo -n "hello" | base64 # encodes "hello" — no newline
Without -n, the newline at the end of the string gets encoded too. When you decode it, you get hello followed by a newline — which can break applications that compare strings. Always use echo -n when encoding secrets.
Updating Secrets¶
Edit in-place¶
Opens the secret in your editor. Values in data are base64-encoded — if you edit them, you must provide base64-encoded values. If you edit stringData, kubectl handles encoding.
Practical problem with kubectl edit: You need to manually base64-encode any new values before pasting them in. Most people use the patch approach instead.
Patch a specific key¶
$(echo -n "newpassword" | base64) — command substitution that encodes the new value inline.
Replace via dry-run + apply¶
kubectl create secret generic db-secret \
--from-literal=password=newpassword \
--dry-run=client -o yaml | kubectl apply -f -
Creates the YAML for the new secret and pipes it into kubectl apply. If the secret already exists, apply updates it. The --dry-run=client means "generate the YAML but don't send it to the API" — then | kubectl apply -f - actually sends it.
Deleting Secrets¶
If a pod is using the secret as an env var, deleting the secret doesn't immediately kill the pod — the env var is baked in at pod start time. But if the pod restarts, it will fail to start (secret not found).
If the secret is mounted as a volume, deleting it will cause the mounted files to disappear (or the pod to fail on the next mount attempt).
envFrom — Inject ALL Keys from a Secret as Env Vars¶
Instead of mapping keys one by one, inject the entire secret:
Every key in the secret becomes an env var in the container. If the secret has password=s3cr3t and username=admin, the container gets env vars password and username.
env vs envFrom — comparison:
# env — map individual keys
env:
- name: DB_PASSWORD # custom env var name
valueFrom:
secretKeyRef:
name: db-secret
key: password # specific key from the secret
# envFrom — inject all keys
envFrom:
- secretRef:
name: db-secret # all keys injected as-is
env lets you rename the key (secret key password → env var DB_PASSWORD). envFrom injects keys directly — the env var name IS the secret key name.
Con of envFrom: If the secret has a key called PATH it will override the system PATH env var. env with explicit mapping is safer and more explicit.
imagePullSecrets — Private Registry Auth¶
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
imagePullSecrets:
- name: my-registry-secret # references a docker-registry type secret
containers:
- name: app
image: registry.example.com/myapp:latest
Without imagePullSecrets, pulling from a private registry fails with ImagePullBackOff and an authentication error.
Immutable Secrets¶
apiVersion: v1
kind: Secret
metadata:
name: db-secret
immutable: true # cannot be edited after creation — must delete and recreate
data:
password: czNjcjN0
Immutable secrets improve performance at scale — Kubernetes doesn't need to watch them for changes. Con: you can't update them. Any change requires deleting and recreating.
RBAC and Secrets — The list vs get Distinction¶
This is a security footgun. Secrets RBAC has a critical difference from other resources:
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"] # can fetch a secret by name if you KNOW the name
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["list"] # can enumerate ALL secrets in the namespace
get requires knowing the secret name. list lets you discover all secrets. Never give list on secrets unless absolutely required — it's essentially giving access to all secrets in the namespace. In production, give get only, scoped to the specific secret name using resourceNames:
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
resourceNames: ["db-secret"] # only THIS specific secret, not all secrets
Secret Size Limit¶
Kubernetes secrets are limited to 1MB. This is a hard limit. For anything larger (certificates chains, large config blobs), use a ConfigMap for non-sensitive data or a mounted volume/external secrets manager for sensitive data.
Quick Reference — All Secret Commands¶
# CREATE
kubectl create secret generic my-secret --from-literal=key=value
kubectl create secret generic my-secret --from-file=file.txt
kubectl create secret generic my-secret --from-file=key=file.txt
kubectl create secret generic my-secret --from-env-file=.env
kubectl create secret tls my-tls --cert=cert.crt --key=cert.key
kubectl create secret docker-registry my-reg --docker-server=x --docker-username=x --docker-password=x
# READ
kubectl get secrets
kubectl get secrets -A
kubectl describe secret my-secret
kubectl get secret my-secret -o yaml
kubectl get secret my-secret -o jsonpath='{.data}'
kubectl get secret my-secret -o jsonpath='{.data.mykey}' | base64 -d
# UPDATE
kubectl edit secret my-secret
kubectl patch secret my-secret -p '{"data":{"key":"'$(echo -n "val" | base64)'"}}'
kubectl create secret generic my-secret --from-literal=key=newval --dry-run=client -o yaml | kubectl apply -f -
# DELETE
kubectl delete secret my-secret
# ENCODE/DECODE
echo -n "plaintext" | base64 # encode
echo "base64string" | base64 -d # decode