Kubernetes ConfigMaps & Secrets Explained (With Practical Examples)
Modern applications rarely run with fixed configuration.
A typical application needs values like:
Database host
Port number
API endpoints
Feature flags
Authentication credentials
If these values are hardcoded inside the application, every small change would require rebuilding and redeploying the application.
This is not scalable.
Kubernetes solves this problem using two powerful resources:
ConfigMaps
Secrets
In this guide, we will understand:
What ConfigMaps are
Why Secrets exist
The difference between ConfigMaps and Secrets
How to use them inside Pods and Deployments
Two ways to inject configuration into containers
The Problem: Hardcoded Configuration
Imagine a backend application connecting to a database.
The application needs values like:
DB_HOST
DB_PORT
DB_USERNAME
DB_PASSWORD
If these values are written directly in code, problems appear immediately:
Database port changes
Credentials rotate
Environment changes (dev → staging → production)
Every change would require modifying code and redeploying the application.
A better design is:
Separate configuration from the application.
This allows the same container image to run in multiple environments.
What is a ConfigMap in Kubernetes?
A ConfigMap is a Kubernetes resource used to store non-sensitive configuration data.
It stores configuration as key-value pairs.
Typical examples include:
application ports
configuration flags
log levels
database host
feature toggles
Example ConfigMap YAML:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DATABASE_PORT: "5432"
LOG_LEVEL: "INFO"
Once created, this ConfigMap can be used by Pods or Deployments.
Applications can read these values through:
Environment variables
Mounted configuration files
Why Kubernetes Has Secrets
Some configuration values are sensitive.
Examples include:
Database passwords
API keys
TLS certificates
OAuth tokens
Storing these inside ConfigMaps would be dangerous.
This is where Secrets are used.
A Secret is designed to store sensitive data securely.
Example Secret:
apiVersion: v1
kind: Secret
metadata:
name: database-secret
type: Opaque
data:
DB_PASSWORD: cGFzc3dvcmQxMjM=
Notice something important:
The value is Base64 encoded.
While Base64 itself is not encryption, Kubernetes supports encryption at rest in etcd.
Where Kubernetes Stores ConfigMaps and Secrets
All Kubernetes resources are stored in etcd, the cluster’s key-value store.
| Resource | Storage |
|---|---|
| ConfigMaps | Stored as plain text |
| Secrets | Stored encoded and can be encrypted at rest |
This difference is the main reason Secrets exist.
ConfigMap vs Secret
| Feature | ConfigMap | Secret |
|---|---|---|
| Purpose | Non-sensitive configuration | Sensitive data |
| Example Data | Ports, URLs, flags | Passwords, tokens |
| Storage | Plaintext in etcd | Encrypted/encoded |
| Security | Basic | Stronger security controls |
| Injection | Env vars or volumes | Env vars or volumes |
Simple rule:
ConfigMaps → configuration
Secrets → credentials
Demo 1 — Creating a ConfigMap
Let's create a simple ConfigMap.
Create a file:
vim database-config.yaml
ConfigMap definition:
apiVersion: v1
kind: ConfigMap
metadata:
name: database-config
data:
DB_PORT: "5432"
Apply it:
kubectl apply -f database-config.yaml
Verify it:
kubectl get configmap
Describe the ConfigMap:
kubectl describe configmap database-config
You should see the stored key-value pair.
Demo 2 — Using ConfigMap as Environment Variables
Now we inject this value into a container.
First, create a deployment file that will consume the ConfigMap.
Create a file:
vim deployment.yaml
Add the following Deployment configuration:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web-container
image: nginx
env:
- name: DATABASE_PORT
valueFrom:
configMapKeyRef:
name: database-config
key: DB_PORT
Apply the deployment:
kubectl apply -f deployment.yaml
Check pods:
kubectl get pods
Enter the container:
kubectl exec -it <pod-name> -- /bin/bash
Check the environment variable:
env | grep DATABASE
Output:
DATABASE_PORT=5432
Your container is now reading configuration from the ConfigMap.
Limitation of Environment Variables
There is one important limitation.
If the ConfigMap value changes, environment variables do not update automatically.
The Pod must be restarted.
In production environments, restarting pods may cause:
traffic disruption
downtime
service instability
So Kubernetes offers another approach.
Demo 3 — Using ConfigMap as a Volume
Instead of environment variables, we can mount the ConfigMap as a file inside the container.
Update the same deployment file (deployment.yaml) created in Demo 2.
Open the file:
vim deployment.yaml
Modify it to include a ConfigMap volume:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web-container
image: nginx
volumeMounts:
- name: config-volume
mountPath: /app/config
volumes:
- name: config-volume
configMap:
name: database-config
Apply the updated deployment:
kubectl apply -f deployment.yaml
Enter the container:
kubectl exec -it <pod-name> -- /bin/bash
Check mounted file:
ls /app/config
You should see:
DB_PORT
Check its value:
cat /app/config/DB_PORT
Output:
5432
Dynamic Updates
Now update the ConfigMap file created in Demo 1 (database-config.yaml).
Open the file:
vim database-config.yaml
Update the value:
DB_PORT: "5433"
Apply the change:
kubectl apply -f database-config.yaml
Wait a few seconds and check inside the container again:
cat /app/config/DB_PORT
The value updates automatically without restarting the Pod.
This is why volume mounts are often preferred.
Creating a Secret
Secrets can also be created using CLI.
Example:
kubectl create secret generic db-credentials \
--from-literal=username=admin \
--from-literal=password=supersecret
Check it:
kubectl get secrets
Describe the secret:
kubectl get secret db-credentials -o yaml
You will see encoded values.
Decoding a Secret
Example encoded value:
c3VwZXJzZWNyZXQ=
Decode it:
echo c3VwZXJzZWNyZXQ= | base64 --decode
Output:
supersecret
This shows that Kubernetes uses Base64 encoding by default.
For production systems, many teams integrate:
HashiCorp Vault
AWS Secrets Manager
Sealed Secrets
Security Best Practices
When working with Secrets:
Use RBAC (Role-Based Access Control).
Follow the principle of least privilege.
Only authorized users should access Secrets.
Developers may need access to:
Pods
Deployments
ConfigMaps
But not necessarily Secrets.
Key Takeaways
ConfigMaps and Secrets are essential tools for managing application configuration in Kubernetes.
Key points to remember:
Never hardcode configuration in containers
Use ConfigMaps for normal configuration
Use Secrets for sensitive information
Environment variables are simple but static
Volume mounts support dynamic updates
Protect Secrets using RBAC and encryption
Understanding these concepts is critical for anyone working with Kubernetes in production.
Final Thoughts
Separating configuration from application code is a fundamental design principle in cloud-native systems.
Kubernetes provides ConfigMaps and Secrets to make this possible in a scalable and secure way.
Once you understand these resources, managing complex applications across multiple environments becomes significantly easier.