๐ Kubernetes - Secrets
The Right Way to Handle Sensitive Data

Weโve already seen how to use ConfigMaps to pass non-sensitive data like configs and files to Pods. If you missed that, you can check it out here.
But now comes the real question:
What about sensitive data?
Passwords? Tokens? SSH keys?
Thatโs where Kubernetes Secrets come in. In this blog, weโll cover:
What are Secrets and why we need them
How to create Secrets
How Pods consume them
Lifecycle & behavior
Security best practices (this is where most people mess up ๐ )
๐ค What are Kubernetes Secrets?
A Secret is a Kubernetes object used to store sensitive data like: Passwords , API tokens, SSH keys , Certificates.
Instead of hardcoding these inside your app or YAML, you decouple them using Secrets.
โ๏ธ How are they different from ConfigMaps?
They look similar to ConfigMaps however they have some distinct behaviour
Stored in etcd (cluster DB)
Mounted as tmpfs (RAM) โ never written to disk ๐ง
Base64 encoded (โ ๏ธ not encryption!)
๐ก Important: Base64 โ Security. Anyone with access can decode it easily.
๐ Why do we need Secrets?
You already know the answer, but letโs reinforce:
Keeps sensitive data out of code
Helps follow 12-factor app principles
Enables secure configuration per environment
You can think of it like this
ConfigMap = app config
Secret = app credentials
๐ ๏ธ How to Create Secrets
You can create Secrets in two ways:
Inline Command
Using YAML
Let's explore them in detail
โก 1. Inline Command (Quick & Dirty)
Example:
# Basic syntax
kubectl create secret <type> <name> --from-literal=<key>=<value>
# Example
kubectl create secret generic api-credentials \
--from-literal=token=super-secret-123
Multi-value example:
kubectl create secret docker-registry private-reg-auth \
--docker-username=my-user \
--docker-password=my-password \
--docker-server=my-registry.io \
--docker-email=my-email@example.com
When to Choose this approach ?
Use this for:
Quick testing
PoCs
Note: Here you can directly pass the values without encoding, Kubernetes encode the value and store it in Etcd
๐ 2. Using YAML (Production Way)
apiVersion: v1
kind: Secret
metadata:
name: my-db-secret
type: Opaque
data:
username: YWRtaW4=
password: MWYyZDNoNGo1aw==
Here you must encode values manually using echo -n "admin" | base64
๐งฉ Secret Types (Quick Understanding)
| Type | Use Case |
|---|---|
Opaque |
Default, anything |
kubernetes.io/dockerconfigjson |
Private registry auth |
kubernetes.io/tls |
TLS cert + key |
kubernetes.io/basic-auth |
Username/password |
kubernetes.io/ssh-auth |
SSH keys |
service-account-token |
Internal API access |
๐ก Tip: Use specific types when possible โ Kubernetes validates structure.
๐ How Pods Consume Secrets
Two main ways (same as ConfigMaps ๐):
Environment Variables
Volume Mounts
๐ก๏ธ Option 1: Environment Variables
This option is suitbale for for API keys or database passwords that the application expects to find in its environment. This is simple and clean approach
Example
apiVersion: v1
kind: Pod
metadata:
name: my-app-pod
spec:
containers:
- name: my-app
image: nginx
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-creds
key: password
โ ๏ธ Cons:
Values are loaded only at startup
If Secret changes โ Pod restart required ๐
๐ Option 2: Volume Mounts (Recommended)
This option is best for certificates, SSH keys, or large configuration files. Kubernetes mounts the secret as a directory where each key in the secret becomes a file.
Example:
apiVersion: v1
kind: Pod
metadata:
name: secret-volume-pod
spec:
containers:
- name: ssh-container
image: nginx
volumeMounts:
- name: ssh-key-vol
mountPath: "/etc/ssh-keys"
readOnly: true
volumes:
- name: ssh-key-vol
secret:
secretName: ssh-key-secret # The name of the Secret object
๐ Each key becomes a file:
/etc/ssh-keys/
โโโ private_key
โโโ public_key
๐ก Why use Volumes over Environment Variables?
Security: Secret volumes are stored in tmpfs (RAM). If the node is powered down, the data vanishes from the node's memory. ๐ง
Updates: If you update a Secret, Kubernetes automatically updates the files in the volume (though this takes a few seconds). Environment variables, however, are staticโyou would have to restart the Pod to see a change. ๐
Structure: Volumes are perfect for things that naturally exist as files, like SSL certificates or SSH
id_rsakeys.
๐ Standard Mount vs. subPath
๐น Standard Mount (Default Behavior)
When you mount a Secret as a volume:
The entire target directory gets replaced
Any existing files become invisible
Only the mounted Secret content is available for your pod to use.
๐ If you mount another Secret to the same path, it will overwrite the previous one
This behavior is intentional in Kubernetes to Ensure data isolation, Improve security, Avoid unintended file conflicts
Now consider a scenario where you want to mount multiple Secrets into the same Pod path.
Using the standard approach:
Mounting Secret A โ works fine
Mounting Secret B to the same path โ overwrites Secret A
๐ Result: The first Secret becomes inaccessible.
To solve this, Kubernetes provides a feature called subPath.
๐ก What is subPath?
subPath allows you to:
Mount individual files or subdirectories
Place them inside an existing directory
Avoid overriding the entire volume path
To know in detail about subpath check here
โ
Using subPath for Multiple Secrets
With subPath, you can mount multiple Secrets into the same directory without conflicts.
Example:
volumeMounts:
- name: secret-a
mountPath: /etc/config/secret-a.txt
subPath: secret-a.txt
- name: secret-b
mountPath: /etc/config/secret-b.txt
subPath: secret-b.txt
volumes:
- name: secret-a
secret:
secretName: secret-a
- name: secret-b
secret:
secretName: secret-b
๐ What happens here?
secret-ais mounted as/etc/config/secret-a.txtsecret-bis mounted as/etc/config/secret-b.txtNo overwriting occurs
Both Secrets coexist in the same directory ๐
One thing to note here is that when using subPath we have to define path with filename and extension whereas in standardMount the mount path is sufficient enough.
LifeCycle for
subPath
One more important thing is that when usingsubPathwhen the secret value is updated it will not update the file directly pod restart is required because here the file is a static bind-mount
๐ Lifecycle of Secrets
In this section we will explore how changing a secret value will be handled in different Consumption option
| Consumption Type | Behavior |
|---|---|
| Env Variables | Deployment Requires restart ๐ |
| Volume Mount | Auto updates โฑ๏ธ |
| subPath | Deployment Requires restart ๐ |
Even though VolumeMount Auto Updates your secrets to the Mount file you app should be configured to pick the updated value.
Security Best Practices & RBAC
Now that we know how to create and consume Secrets, Let's talk about how to actually keep them "secret."
Even though Secrets are better than plain-text ConfigMaps, they have some vulnerabilities by default:
Base64 is not encryption: It's just a way to store binary data as text. Anyone who can run
kubectl get secret -o yamlcan see your passwords. ๐Etcd Storage: By default, Secrets are stored in plain text in the cluster's database (
etcd).
Some of the best practices
Encryption at Rest (The Native Way)
You can configure the Kubernetes API server with an EncryptionConfiguration file. When this is enabled, the API server will mathematically encrypt the Secret data before it saves it to etcd. Even if someone steals the etcd hard drive, the data is unreadable garbage without the encryption key.
Strict RBAC (Role-Based Access Control)
As we discussed briefly before, you must restrict who can run kubectl get secrets. If a developer has the get or list permission for Secrets, they can just ask the API server to show them the Base64 data, bypassing all etcd encryption. You should only grant Secret access to the specific ServiceAccounts that the Pods use, not to human users.
To truly secure a Secret while still letting it be used:
For Users (Developers): You generally want to deny get, list, and watch. If they can't get it, they can't see the password.
For Pods: The Pod doesn't actually need the user to have permissions. The Pod uses a ServiceAccount. The Kubernetes controller-manager handles the mounting process, so as long as the Pod's YAML is allowed to be created, the system handles the rest.
External Secret Stores (The Enterprise Way)
In large companies, they don't even store the source-of-truth secrets in Kubernetes at all! They use tools like HashiCorp Vault, AWS Secrets Manager, or Azure Key Vault. They use plugins (like the Secrets Store CSI Driver or External Secrets Operator) to fetch the password from the cloud vault and inject it directly into the Pod at runtime.
Conclusion
Kubernetes Secrets might look simple at first, but how you use them makes all the difference. They help you keep sensitive data out of your code and configsโbut they are not secure by default.
If you use them the right way prefer volumes over env vars, restrict access with RBAC, and integrate with external secret managersโyou move from just โworking setupโ to a production-ready secure system ๐
Thanks for reading. Keep learning, keep building, and keep breaking things (thatโs how we grow) . See you in the next one โ๏ธ



