Skip to content

Kubernetes Secrets — Commands Reference

Reference: https://kubernetes.io/docs/concepts/configuration/secret/

See also: secret_1.md.md for 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

kubectl create secret generic my-secret \
  --from-literal=mykey=mysecretvalue

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

kubectl create secret generic my-secret \
  --from-file=database-data.txt

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:

kubectl create secret generic my-secret \
  --from-file=mykey=database-data.txt

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

kubectl create secret tls my-tls-secret \
  --cert=path/to/cert.crt \
  --key=path/to/cert.key

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)

kubectl create secret generic db-secret \
  --from-literal=password=s3cr3t \
  --dry-run=client -o yaml

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

kubectl describe secret db-secret

Output:

Name:         db-secret
Namespace:    default
Type:         Opaque

Data
====
password:  8 bytes
username:  5 bytes

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

kubectl get secret db-secret -o yaml

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):

kubectl get secret db-secret -o jsonpath='{.data.password}' | base64 -d

Write to a file:

kubectl get secret db-secret -o jsonpath='{.data.password}' | base64 -d > /tmp/decoded-password.txt

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

kubectl edit secret db-secret

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

kubectl patch secret db-secret \
  -p '{"data":{"password":"'$(echo -n "newpassword" | base64)'"}}'

$(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

kubectl delete secret db-secret
kubectl delete secret db-secret -n my-namespace

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:

envFrom:
- secretRef:
    name: db-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