Secrets decouple confidential values (DB passwords, API keys, TLS certs) from container images and Pod definitions, enabling independent lifecycle management.
Interactive guide to storing and consuming sensitive data — passwords, tokens, TLS certificates, and SSH keys — without baking them into images or manifests.
A Secret holds confidential data in base64-encoded form and is delivered to Pods through environment variables or volume mounts. Kubernetes keeps Secrets separate from Pod specs so you can manage access, rotation, and audit independently.
Secrets decouple confidential values (DB passwords, API keys, TLS certs) from container images and Pod definitions, enabling independent lifecycle management.
Values are base64-encoded in the API, not encrypted by default. Enable etcd encryption-at-rest or use an external secret store for real protection.
Inject as environment variables (secretKeyRef) for simple access, or mount as files (volumeMount) for certificates and config files that apps expect on disk.
Secrets live in a namespace. A Pod can only reference Secrets in the same namespace, keeping blast radius contained.
kubectl get configmap -o yaml.| Type | Value of type: | Typical Use |
|---|---|---|
| Opaque | Opaque | General purpose — arbitrary key/value pairs (default) |
| Docker Registry | kubernetes.io/dockerconfigjson | Image pull credentials for private registries |
| TLS | kubernetes.io/tls | TLS certificate + private key pair |
| Basic Auth | kubernetes.io/basic-auth | Username / password pair |
| SSH Auth | kubernetes.io/ssh-auth | SSH private key |
| Token | bootstrap.kubernetes.io/token | Bootstrap token for node joining |
| Service Account | kubernetes.io/service-account-token | Auto-mounted SA token (legacy; BoundServiceAccountTokenVolume is the modern path) |
type: field when creating a Secret so Kubernetes can validate required keys (e.g. tls.crt + tls.key for TLS secrets).# From literal values
kubectl create secret generic db-credentials \
--from-literal=username=admin \
--from-literal=password='p@ssw0rd'
# From a file
kubectl create secret generic tls-cert \
--from-file=tls.crt=./server.crt \
--from-file=tls.key=./server.key
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
data: # base64-encoded values
username: YWRtaW4= # echo -n 'admin' | base64
password: cEBzc3cwcmQ= # echo -n 'p@ssw0rd' | base64
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
stringData: # Kubernetes base64-encodes these for you
api-key: my-super-secret-key
connection-string: "postgresql://user:pass@db:5432/mydb"
# Imperative
kubectl create secret tls my-tls-secret \
--cert=./tls.crt \
--key=./tls.key
# Declarative
apiVersion: v1
kind: Secret
metadata:
name: my-tls-secret
type: kubernetes.io/tls
data:
tls.crt: LS0tLS1CRUdJTi... # base64 of cert PEM
tls.key: LS0tLS1CRUdJTi... # base64 of key PEM
kubectl create secret docker-registry regcred \
--docker-server=https://index.docker.io/v1/ \
--docker-username=myuser \
--docker-password=mypass \
--docker-email=me@example.com
# Reference in a Pod spec
spec:
imagePullSecrets:
- name: regcred
apiVersion: v1
kind: Pod
metadata:
name: secret-env-pod
spec:
containers:
- name: app
image: busybox
command: ["sh", "-c", "echo $DB_USER $DB_PASS && sleep 3600"]
env:
- name: DB_USER
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DB_PASS
valueFrom:
secretKeyRef:
name: db-credentials
key: password
apiVersion: v1
kind: Pod
metadata:
name: secret-vol-pod
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: creds
mountPath: /etc/secrets
readOnly: true
volumes:
- name: creds
secret:
secretName: db-credentials
defaultMode: 0400 # read-only for owner
| Aspect | Secret | ConfigMap |
|---|---|---|
| Purpose | Sensitive / confidential data | Non-sensitive configuration |
| Encoding | Base64 by default; supports stringData | Plain text |
| Size limit | 1 MiB per Secret | 1 MiB per ConfigMap |
| etcd storage | Encrypted-at-rest when configured | Stored in plain text |
| RBAC | Typically restricted to specific roles | Often broader access |
| Volume default mode | 0644 (recommended: 0400) | 0644 |
| Typed validation | Yes — type: enforces required keys | No typed enforcement |
| Auto-update (volume) | Yes (~1 min kubelet sync) | Yes (~1 min kubelet sync) |
| Auto-update (env) | No — Pod restart required | No — Pod restart required |
get configmap permissions.Configure EncryptionConfiguration on the API server so Secrets are encrypted in etcd rather than stored as plain base64.
Limit get, list, and watch on Secrets to service accounts and users that genuinely need them.
For production, integrate with HashiCorp Vault, AWS Secrets Manager, or GCP Secret Manager via CSI driver or operator (e.g. External Secrets Operator).
Env vars appear in /proc, crash dumps, and logs. Prefer volume mounts with readOnly: true and restricted defaultMode.
Treat Secrets as ephemeral. Update values and perform a rolling restart; automate rotation with controllers.
Add Secret YAML files to .gitignore. Use sealed-secrets or SOPS if you need GitOps workflows for sensitive data.
echo <value> | base64 -d.| Action | Command |
|---|---|
| Create from literals | kubectl create secret generic NAME --from-literal=key=value |
| Create from file | kubectl create secret generic NAME --from-file=key=filepath |
| Create TLS secret | kubectl create secret tls NAME --cert=path --key=path |
| Create docker-registry | kubectl create secret docker-registry NAME --docker-server=... --docker-username=... --docker-password=... |
| List secrets | kubectl get secrets |
| Describe (metadata only) | kubectl describe secret NAME |
| View decoded value | kubectl get secret NAME -o jsonpath='{.data.key}' | base64 -d |
| Edit in-place | kubectl edit secret NAME |
| Delete | kubectl delete secret NAME |
| Dry-run YAML generation | kubectl create secret generic NAME --from-literal=k=v --dry-run=client -o yaml |
Store DB username and password in a Secret, reference via secretKeyRef in the Deployment. Rotate by updating the Secret and performing a rolling restart.
Create a kubernetes.io/tls Secret and reference it in an Ingress resource for HTTPS termination at the ingress controller.
Create a docker-registry Secret and reference it via imagePullSecrets in the Pod spec or patch it into the ServiceAccount.
Mount an ssh-auth Secret into a sidecar that pulls code from a private Git repository.
Use a ConfigMap for app settings and a Secret for credentials; mount both into the same Pod for a clean separation of concerns.
Set immutable: true on Secrets that should never change (K8s 1.21+). Protects against accidental edits and improves kubelet performance.