Warrior, now we move from Kubernetes infrastructure to something you'll use constantly in real applications:
How does your application get configuration and sensitive values inside Kubernetes?
For example, your Node.js application may need:
NODE_ENV=production
PORT=3000
DATABASE_URL=...
REDIS_HOST=redis-service
JWT_SECRET=...
OPENAI_API_KEY=...You should not hardcode these values into your source code or Docker image.
Kubernetes gives us two major objects:
ConfigMap → non-sensitive configuration
Secret → sensitive dataSuppose your Node.js code contains:
const databaseUrl =
"postgresql://admin:password123@postgres:5432/mydb";This is a bad practice.
Why?
Because the secret is now inside your:
Source code
↓
Git
↓
Docker image
↓
DeploymentAnyone with access to the repository/image may potentially see it.
Instead:
Node.js Application
↑
│
Environment
Variables
↑
┌────┴─────┐
│ │
ConfigMap SecretA ConfigMap stores non-sensitive configuration data.
Examples:
NODE_ENV=production
PORT=3000
API_URL=https://api.example.com
LOG_LEVEL=info
REDIS_HOST=redis-serviceDon't use ConfigMap for passwords, API keys, tokens, etc.
kubectl create configmap app-config \
--from-literal=NODE_ENV=production \
--from-literal=PORT=3000Check:
kubectl get configmapsor:
kubectl get cmThe declarative approach is:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
NODE_ENV: "production"
PORT: "3000"
LOG_LEVEL: "info"Apply:
kubectl apply -f configmap.yamlCheck:
kubectl get configmap app-configTo see its contents:
kubectl describe configmap app-configCreating a ConfigMap isn't enough.
Your application needs to consume it.
Example:
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-api
spec:
replicas: 2
selector:
matchLabels:
app: node-api
template:
metadata:
labels:
app: node-api
spec:
containers:
- name: node-api
image: my-node-api:1.0
envFrom:
- configMapRef:
name: app-configNow Kubernetes injects:
NODE_ENV
PORT
LOG_LEVELinto the container's environment.
envFrom Do?#This:
envFrom:
- configMapRef:
name: app-configmeans:
Take all key-value pairs from
app-configand make them environment variables inside the container.
So:
data:
NODE_ENV: "production"
PORT: "3000"becomes:
Container
NODE_ENV=production
PORT=3000Your Node.js application can then use:
console.log(process.env.NODE_ENV);
console.log(process.env.PORT);For example:
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server running on ${port}`);
});Your application doesn't need to know where the configuration came from.
You don't always want every ConfigMap value.
Suppose:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
NODE_ENV: "production"
PORT: "3000"
LOG_LEVEL: "info"You can select only one:
env:
- name: NODE_ENV
valueFrom:
configMapKeyRef:
name: app-config
key: NODE_ENVNow only:
NODE_ENVis injected.
ConfigMaps can also be mounted as files.
Example:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: config
mountPath: /etc/myconfig
volumes:
- name: config
configMap:
name: app-configKubernetes can expose the ConfigMap data as files inside:
/etc/myconfigThis is useful for configuration files such as:
nginx.conf
application.properties
config.jsonThis is extremely important.
A Secret stores sensitive configuration.
Examples:
DATABASE_PASSWORD
JWT_SECRET
API_KEY
AWS_ACCESS_KEY
OAuth credentials
TLS certificatesConceptually:
ConfigMap
↓
Public/non-sensitive configuration
Secret
↓
Sensitive configurationImperative:
kubectl create secret generic db-secret \
--from-literal=DB_USER=admin \
--from-literal=DB_PASSWORD=myPassword123Check:
kubectl get secretsYou might see:
NAME TYPE DATA
db-secret Opaque 2Notice Kubernetes doesn't normally display the values in kubectl get secrets.
You may see Secrets written like:
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
DB_USER: YWRtaW4=
DB_PASSWORD: bXlQYXNzd29yZDEyMw==Those values are Base64 encoded.
For example:
adminbecomes:
YWRtaW4=This is one of the most important Kubernetes interview questions.
If you see:
YWRtaW4=you can decode it.
For example:
echo "YWRtaW4=" | base64 --decodeResult:
adminTherefore:
Kubernetes Secret data being Base64 encoded does NOT mean the data is encrypted.
Think:
Base64
↓
Encodingnot:
Base64
↓
EncryptionstringData#Instead of manually encoding values, you can use:
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
stringData:
DB_USER: admin
DB_PASSWORD: myPassword123Kubernetes handles the conversion.
This is convenient, but putting plaintext secrets in Git is still a security problem.
For production, teams often use external secret-management systems such as:
AWS Secrets Manager
Azure Key Vault
Google Secret Manager
HashiCorp Vault
External Secrets OperatorJust like ConfigMap:
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-api
spec:
replicas: 2
selector:
matchLabels:
app: node-api
template:
metadata:
labels:
app: node-api
spec:
containers:
- name: node-api
image: my-node-api:1.0
envFrom:
- secretRef:
name: db-secretNow the container receives:
DB_USER
DB_PASSWORDas environment variables.
This is a very common real-world pattern.
containers:
- name: node-api
image: my-node-api:1.0
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: db-secretArchitecture:
Node.js Pod
│
┌──────────┴──────────┐
│ │
ConfigMap Secret
│ │
non-sensitive sensitive
│ │
└──────────┬──────────┘
│
Environment
VariablesImagine your application needs:
NODE_ENV
PORT
DATABASE_URL
REDIS_HOST
JWT_SECRETWe can separate them.
apiVersion: v1
kind: ConfigMap
metadata:
name: node-api-config
data:
NODE_ENV: "production"
PORT: "3000"
REDIS_HOST: "redis-service"apiVersion: v1
kind: Secret
metadata:
name: node-api-secret
type: Opaque
stringData:
DATABASE_URL: "postgresql://admin:password@postgres:5432/app"
JWT_SECRET: "super-secret-key"apiVersion: apps/v1
kind: Deployment
metadata:
name: node-api
spec:
replicas: 3
selector:
matchLabels:
app: node-api
template:
metadata:
labels:
app: node-api
spec:
containers:
- name: node-api
image: my-node-api:1.0
ports:
- containerPort: 3000
envFrom:
- configMapRef:
name: node-api-config
- secretRef:
name: node-api-secretYour Node.js application can simply do:
const {
NODE_ENV,
PORT,
DATABASE_URL,
REDIS_HOST,
JWT_SECRET
} = process.env;This is the mental model I want you to remember:
Kubernetes
│
┌───────────┴───────────┐
│ │
ConfigMap Secret
│ │
│ │
└───────────┬───────────┘
│
Deployment
│
▼
Pod
│
▼
Node.js Container
│
▼
process.env.*Don't confuse these concepts.
PORT=3000is simply a value available to the process.
PORT=3000is Kubernetes-managed configuration that can be injected into the application.
So:
ConfigMap → source of configuration
Environment variable → one way to deliver it to applicationSecrets deserve special attention.
A common misconception is:
"If it's a Kubernetes Secret, it's automatically completely secure."
That's not correct.
You need to consider:
RBAC
↓
Who can read the Secret?
API Server
↓
How is it accessed?
etcd
↓
How is it stored?
Encryption at rest
↓
Is etcd data encrypted?
External secret manager
↓
Can sensitive credentials stay outside Kubernetes?Kubernetes supports encryption at rest for Secret data, but the exact configuration depends on the cluster.
Don't commit:
stringData:
DATABASE_PASSWORD: "MyRealPassword123"to a public Git repository.
Also avoid:
const password = "MyRealPassword123";inside application code.
And don't bake secrets into a Dockerfile:
ENV DATABASE_PASSWORD="MyRealPassword123"Bad idea.
A more mature architecture looks like:
Developer
│
▼
Git Repository
│
│ application code
▼
Docker Image
│
▼
Kubernetes
│
├── ConfigMap
│
└── External Secret Manager
│
├── AWS Secrets Manager
├── Azure Key Vault
├── GCP Secret Manager
└── VaultThe application receives the values at runtime.
| Feature | ConfigMap | Secret |
|---|---|---|
| Purpose | Configuration | Sensitive data |
| Passwords | ❌ | ✅ |
| API keys | ❌ | ✅ |
NODE_ENV |
✅ | ❌ |
PORT |
✅ | ❌ |
| Base64 encoding | No requirement | Commonly used |
| Encryption | Not inherently | Can be encrypted at rest |
| Environment variables | ✅ | ✅ |
| Volume mount | ✅ | ✅ |
Suppose your ConfigMap contains:
LOG_LEVEL=infoand you change it to:
LOG_LEVEL=debugWhat happens to your application?
It depends on how the ConfigMap is consumed.
If injected as environment variables:
envFrom:
- configMapRef:
name: app-configexisting containers do not automatically receive the changed environment variable.
You generally need to restart/recreate the Pods.
For example:
kubectl rollout restart deployment node-apiIf a ConfigMap is mounted as a volume, Kubernetes can update the mounted files eventually, although applications may still need to reload the configuration themselves.
This distinction is important in production.
Another common interview question.
If:
ConfigMap changesKubernetes does not automatically perform a Deployment rollout merely because the ConfigMap changed.
Common deployment tooling patterns use annotations/checksums or explicitly trigger a rollout.
For example:
kubectl rollout restart deployment/node-apiLet's create a small setup.
kubectl create namespace config-demokubectl create configmap app-config \
--from-literal=APP_NAME=MyNodeApp \
--from-literal=APP_ENV=development \
-n config-demokubectl create secret generic app-secret \
--from-literal=API_KEY=my-secret-key \
-n config-demoapiVersion: v1
kind: Pod
metadata:
name: config-demo
namespace: config-demo
spec:
containers:
- name: app
image: busybox
command: ["sh", "-c", "env; sleep 3600"]
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: app-secretApply:
kubectl apply -f pod.yamlkubectl exec -it config-demo -n config-demo -- shThen:
envYou should find:
APP_NAME=MyNodeApp
APP_ENV=development
API_KEY=my-secret-keyCongratulations—you've just injected Kubernetes configuration into a container.
kubectl get configmapskubectl get cmkubectl describe configmap app-configkubectl get secretskubectl describe secret app-secretkubectl create configmap app-config \
--from-literal=KEY=valuekubectl create secret generic app-secret \
--from-literal=KEY=valuekubectl delete configmap app-configkubectl delete secret app-secretA Kubernetes object used to store non-sensitive configuration data separately from application code and container images.
A Kubernetes object intended for sensitive data such as passwords, tokens, and API keys.
Don't simply say "yes."
A better answer:
Secret data is commonly represented using Base64 in Kubernetes manifests/API responses, which is encoding rather than encryption. Kubernetes supports encryption at rest, but whether it is configured depends on the cluster.
Two common methods:
Environment variables
OR
Mounted filesAgain:
Environment variables
OR
Mounted filesNo.
Use Secrets or, preferably for many production environments, an integrated external secret-management system.
No.
Especially when consumed as environment variables, existing Pods retain their existing environment until recreated/restarted.
ConfigMap
↓
Non-sensitive configuration
Secret
↓
Sensitive configuration
Deployment
↓
envFrom
↓
ConfigMap / Secret
↓
Container
↓
process.envRemember:
ConfigMap = configuration Secret = sensitive configuration
And the most important security lesson:
Base64 is encoding, not encryption.
CLUSTER
│
┌─────────────┴─────────────┐
│ │
DEV PROD
│ │
┌─────┴─────┐ ┌─────┴─────┐
│ │ │ │
Deployment Service Deployment Service
│ │
ReplicaSet ReplicaSet
│ │
Pods Pods
│ │
Containers Containers
↑ ↑
ConfigMap ConfigMap
Secret SecretYou now understand how an application is deployed and how configuration reaches it.
We'll solve another major container problem:
"What happens to my data when the Pod dies?"
You'll learn:
Volumes → emptyDir → PersistentVolume → PersistentVolumeClaim → StorageClass → dynamic provisioning → Stateful applications like PostgreSQL.
Mark it as complete to track your mastery.