Chapter 6: ConfigMaps & Secrets
Authored by syscook.dev
What are ConfigMaps and Secrets?
ConfigMaps and Secrets are Kubernetes objects that allow you to decouple configuration data from application code. ConfigMaps store non-sensitive configuration data, while Secrets store sensitive information like passwords, tokens, and keys.
Key Concepts:
- ConfigMaps: Store configuration data as key-value pairs
- Secrets: Store sensitive data in base64 encoded format
- Environment Variables: Inject configuration into containers
- Volume Mounts: Mount configuration files into containers
- Data Sources: Create from files, directories, or literals
- Security: Encryption at rest and in transit
Why Use ConfigMaps and Secrets?
1. Configuration Management
Separate configuration from application code for better maintainability.
# Example: ConfigMap for application configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: production
labels:
app: web-app
data:
# Configuration data
database.host: "postgres-service"
database.port: "5432"
database.name: "myapp"
app.environment: "production"
app.log_level: "info"
app.max_connections: "100"
# Configuration file
nginx.conf: |
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
location /health {
access_log off;
return 200 "healthy\n";
}
}
2. Secret Management
Securely store and manage sensitive information.
# Example: Secret for database credentials
apiVersion: v1
kind: Secret
metadata:
name: database-secret
namespace: production
labels:
app: web-app
type: Opaque
data:
# Base64 encoded values
username: cG9zdGdyZXM= # postgres
password: cGFzc3dvcmQ= # password
host: cG9zdGdyZXMtc2VydmljZQ== # postgres-service
port: NTQzMg== # 5432
stringData:
# Plain text values (automatically base64 encoded)
database_url: "postgres://postgres:password@postgres-service:5432/myapp"
api_key: "abc123def456"
How to Use ConfigMaps and Secrets?
1. ConfigMap Configuration
From Literal Values
# Example: ConfigMap from literal values
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: production
data:
database.host: "postgres-service"
database.port: "5432"
database.name: "myapp"
app.environment: "production"
app.log_level: "info"
app.max_connections: "100"
app.timeout: "30s"
app.retry_attempts: "3"
From Files
# Example: ConfigMap from files
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
namespace: production
data:
nginx.conf: |
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
location /health {
access_log off;
return 200 "healthy\n";
}
}
default.conf: |
upstream backend {
server api-service:8080;
}
server {
listen 80;
server_name api.localhost;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
2. Secret Configuration
Basic Secret
# Example: Basic secret
apiVersion: v1
kind: Secret
metadata:
name: app-secret
namespace: production
type: Opaque
data:
username: YWRtaW4= # admin
password: cGFzc3dvcmQ= # password
token: YWJjZGVmZ2hpams= # abcdefghijk
TLS Secret
# Example: TLS secret
apiVersion: v1
kind: Secret
metadata:
name: tls-secret
namespace: production
type: kubernetes.io/tls
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t...
tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQ...
3. Using in Pods
Environment Variables
# Example: Pod using ConfigMap and Secret as environment variables
apiVersion: v1
kind: Pod
metadata:
name: web-app-pod
namespace: production
spec:
containers:
- name: web-server
image: nginx:1.20
ports:
- containerPort: 80
env:
# From ConfigMap
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: database.host
- name: DATABASE_PORT
valueFrom:
configMapKeyRef:
name: app-config
key: database.port
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: app.log_level
# From Secret
- name: DATABASE_USERNAME
valueFrom:
secretKeyRef:
name: database-secret
key: username
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: database-secret
key: password
# All ConfigMap data as environment variables
- name: CONFIG_MAP_DATA
valueFrom:
configMapKeyRef:
name: app-config
optional: true
# All Secret data as environment variables
- name: SECRET_DATA
valueFrom:
secretKeyRef:
name: app-secret
optional: true
Volume Mounts
# Example: Pod using ConfigMap and Secret as volume mounts
apiVersion: v1
kind: Pod
metadata:
name: web-app-pod
namespace: production
spec:
containers:
- name: web-server
image: nginx:1.20
ports:
- containerPort: 80
volumeMounts:
- name: config-volume
mountPath: /etc/nginx/conf.d
readOnly: true
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: config-volume
configMap:
name: nginx-config
items:
- key: nginx.conf
path: nginx.conf
- key: default.conf
path: default.conf
- name: secret-volume
secret:
secretName: app-secret
items:
- key: username
path: username
- key: password
path: password
- key: token
path: token
Practical Examples
1. Complete Application Configuration
Step 1: Create ConfigMaps
#!/bin/bash
# create-configmaps.sh
kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: production
data:
database.host: "postgres-service"
database.port: "5432"
database.name: "myapp"
app.environment: "production"
app.log_level: "info"
app.max_connections: "100"
app.timeout: "30s"
app.retry_attempts: "3"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
namespace: production
data:
nginx.conf: |
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
location /health {
access_log off;
return 200 "healthy\n";
}
}
EOF
echo "ConfigMaps created successfully!"
Step 2: Create Secrets
#!/bin/bash
# create-secrets.sh
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: database-secret
namespace: production
type: Opaque
stringData:
username: "postgres"
password: "password123"
host: "postgres-service"
port: "5432"
database_url: "postgres://postgres:password123@postgres-service:5432/myapp"
---
apiVersion: v1
kind: Secret
metadata:
name: app-secret
namespace: production
type: Opaque
stringData:
api_key: "abc123def456"
jwt_secret: "jwt-secret-key"
encryption_key: "encryption-key-123"
EOF
echo "Secrets created successfully!"
Step 3: Use in Deployment
#!/bin/bash
# create-deployment-with-config.sh
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-deployment
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-server
image: nginx:1.20
ports:
- containerPort: 80
env:
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: database.host
- name: DATABASE_PORT
valueFrom:
configMapKeyRef:
name: app-config
key: database.port
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: app.log_level
- name: DATABASE_USERNAME
valueFrom:
secretKeyRef:
name: database-secret
key: username
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: database-secret
key: password
volumeMounts:
- name: config-volume
mountPath: /etc/nginx/conf.d
readOnly: true
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: config-volume
configMap:
name: nginx-config
- name: secret-volume
secret:
secretName: app-secret
EOF
echo "Deployment with configuration created successfully!"
Best Practices
1. Security Configuration
# Good: Use proper secret types
apiVersion: v1
kind: Secret
metadata:
name: tls-secret
namespace: production
type: kubernetes.io/tls
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t...
tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQ...
2. Configuration Organization
# Good: Organized configuration structure
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: production
labels:
app: web-app
tier: frontend
data:
# Database configuration
database.host: "postgres-service"
database.port: "5432"
database.name: "myapp"
# Application configuration
app.environment: "production"
app.log_level: "info"
app.max_connections: "100"
# Feature flags
features.new_ui: "true"
features.analytics: "false"
3. Volume Mount Configuration
# Good: Proper volume mount configuration
volumeMounts:
- name: config-volume
mountPath: /etc/nginx/conf.d
readOnly: true
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
subPath: username
Common Pitfalls and Solutions
1. Secret Encoding Issues
# ❌ Problem: Secret not properly encoded
# Error: invalid base64
# ✅ Solution: Use stringData for plain text
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
stringData:
username: "admin"
password: "password123"
2. ConfigMap Key Issues
# ❌ Problem: ConfigMap key not found
# Error: key not found
# ✅ Solution: Check key names and make them optional
env:
- name: CONFIG_VALUE
valueFrom:
configMapKeyRef:
name: app-config
key: config.value
optional: true
3. Volume Mount Issues
# ❌ Problem: Volume mount fails
# Error: path not found
# ✅ Solution: Check mount path and permissions
volumeMounts:
- name: config-volume
mountPath: /etc/nginx/conf.d
readOnly: true
Conclusion
ConfigMaps and Secrets are essential for managing configuration and sensitive data in Kubernetes. By understanding:
- What ConfigMaps and Secrets are and their purposes
- Why they're important for configuration management and security
- How to use them effectively in applications
You can create maintainable and secure applications that separate configuration from code. Proper use ensures that your applications are configurable, secure, and easy to manage across different environments.
Next Steps
- Practice with different configuration scenarios
- Learn about volumes and storage
- Move on to Chapter 7: Volumes & Storage
This tutorial is part of the Kubernetes Mastery series by syscook.dev