Kubernetes Bootcamp: ConfigMaps & Secrets
ConfigMaps and Secrets decouple runtime configuration parameters, application settings, and confidential credentials from application container images. This chapter covers the architecture, injection mechanisms, security trade-offs, and practical YAML implementations of ConfigMaps and Secrets, including private registry authentication and production-grade secret management frameworks.
1. The Architecture of Configuration Decoupling
Hardcoding configuration data or database credentials inside container images creates rigid deployment cycles and security vulnerabilities. Rebuilding an entire container image just to change a log level or a database endpoint violates cloud-native design principles.
Kubernetes decouples runtime configurations into dedicated API objects: ConfigMaps (for non-confidential data) and Secrets (for confidential data).
By keeping container images immutable across environments, the exact same image can run in Development, Staging, and Production simply by binding different ConfigMaps or Secrets to the deployment specification.
2. Deep Dive into ConfigMaps
A ConfigMap is a native Kubernetes object designed to store non-confidential key-value pairs or complete configuration files.
The 4 Methods of Injecting ConfigMaps into Pods
- Environment Variables: Inject key-value pairs directly as environment variables inside the container using
valueFromorenvFrom. - Container Command / Arguments: Pass ConfigMap values as arguments to the entrypoint command of the container.
- Volume Mounts: Mount ConfigMap keys as individual files inside a directory tree within the container filesystem.
- Programmatic API Access: Write application code using Kubernetes SDKs (e.g., Python, Go, Java clients) to query the Kubernetes API Server directly and read ConfigMaps dynamically.
ConfigMap Immutability & Lifecycle Mechanics
apiVersion: v1
kind: ConfigMap
metadata:
name: dynamic-config
immutable: true # Prevents unexpected runtime modification
data:
APP_MODE: "production"
- Immutability (
immutable: true): Adding this field locks the ConfigMap against unintended edits. This improves performance by reducing load onkube-apiserver, askubeletstops watching the object for updates. - Update Propagation:
- Environment Variables: Changes to a ConfigMap do not automatically update running container environment variables. The Pod must be restarted.
- Volume Mounts: Updates to mounted ConfigMaps are updated on the container filesystem automatically by
kubelet(typically within seconds), provided nosubPathmounting was used.
3. Practical ConfigMap Implementation Patterns
Pattern A: Environment Variable Injection
This pattern extracts scalar values from a ConfigMap and exposes them to the application runtime environment.
cm-env.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: bootcamp-config
data:
username: "sayam"
database_name: "example_db"
pod-env.yaml
apiVersion: v1
kind: Pod
metadata:
name: mysql-config-demo
spec:
containers:
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_USER
valueFrom:
configMapKeyRef:
name: bootcamp-config
key: username
- name: MYSQL_DATABASE
valueFrom:
configMapKeyRef:
name: bootcamp-config
key: database_name
- name: MYSQL_ROOT_PASSWORD
value: "demo345" # Hardcoded for demo; bad practice!
ports:
- containerPort: 3306
Pattern B: Mounting Configuration Files via Volume Mounts
When an application expects a configuration file on a specific filesystem path (e.g., /etc/config/settings.properties), ConfigMaps can mount multiline text strings directly as files.
cm-file.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-settings-dev
data:
settings.properties: |
debug=true
database.url=jdbc:mysql://dev-db.internal:3306/dev_db
logging.level=DEBUG
pod-file.yaml
apiVersion: v1
kind: Pod
metadata:
name: web-app-dev
spec:
containers:
- name: nginx
image: nginx:alpine
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: app-settings-dev
When this Pod initializes, Kubernetes creates a file at /etc/config/settings.properties containing the block defined in the ConfigMap.
# Executing into container to verify file content
kubectl exec -it web-app-dev -- cat /etc/config/settings.properties
Pattern C: Programmatic API Access using SDKs
For specialized applications or operators that need to read dynamic cluster configs directly from the API server without restart cycles, native language SDKs are utilized.
app.py (Python Kubernetes Client)
from kubernetes import client, config
# Load in-cluster configuration
config.load_incluster_config()
v1 = client.CoreV1Api()
def fetch_config_map(name, namespace="default"):
try:
cm = v1.read_namespaced_config_map(name=name, namespace=namespace)
print(f"Fetched ConfigMap Data: {cm.data}")
for key, value in cm.data.items():
print(f"Key: {key} -> Value: {value}")
except Exception as e:
print(f"Error reading ConfigMap: {e}")
if __name__ == "__main__":
fetch_config_map("app-settings-dev")
4. Kubernetes Secrets: Types & Security Realities
A Secret is an API object intended to hold confidential information such as passwords, OAuth tokens, SSH keys, or SSL/TLS certificates.
The Base64 Encoding Fallacy
Note: By default, standard Kubernetes Secrets are NOT encrypted; they are merely Base64-encoded. Base64 is an encoding scheme, not encryption. Anyone with
GETaccess to Secrets or read access to the cluster's underlyingetcddatastore can decode the values instantly.
# Base64 Encoding a raw string
echo -n "SuperSecretPassword123" | base64
# Output: U3VwZXJTZWNyZXRQYXNzd29yZDEyMw==
# Base64 Decoding a secret back to plain text
echo "U3VwZXJTZWNyZXRQYXNzd29yZDEyMw==" | base64 --decode
# Output: SuperSecretPassword123
Native Kubernetes Secret Types
5. Declarative and Imperative Secret Creation
Method 1: Imperative Command-Line Creation
Imperative commands avoid writing plain-text passwords into YAML manifests that might accidentally be committed to version control.
# Create a generic Opaque Secret from literals
kubectl create secret generic db-credentials \
--from-literal=username='admin' \
--from-literal=password='ComplexP@ss123'
# Create a Secret from file contents
kubectl create secret generic ssh-key-secret \
--from-file=ssh-privatekey=~/.ssh/id_rsa
# Create a Basic Auth Secret
kubectl create secret basic-auth my-basic-auth \
--username=admin \
--password=secretpass
Method 2: Declarative Manifest (Requires Pre-Encoded Base64 Strings)
When authoring Secret manifests, raw plain text cannot be used in the data block. All string values must be pre-encoded into Base64. Alternatively, strings can be placed under stringData in plain text (Kubernetes will base64-encode them automatically upon storage).
secret-opaque.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysql-secrets
type: Opaque
data:
# Values pre-encoded via: echo -n '<value>' | base64
MYSQL_ROOT_PASSWORD: YWJjMTIz # Base64 for "abc123"
MYSQL_USER_PASSWORD: c2F5YW1wYXNz # Base64 for "sayampass"
6. Injecting Secrets into Workloads
Just like ConfigMaps, Secrets can be exposed as environment variables or mounted as filesystem volumes.
apiVersion: v1
kind: Pod
metadata:
name: secure-mysql-pod
spec:
containers:
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secrets
key: MYSQL_ROOT_PASSWORD
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secrets
key: MYSQL_USER_PASSWORD
ports:
- containerPort: 3306
7. Authenticating Private Registries (imagePullSecrets)
When pulling container images hosted in private Docker repositories (e.g., private Docker Hub, Quay.io, AWS ECR), the Kubernetes cluster node (kubelet) must authenticate before downloading the image layers.
Workflow: Pulling Private Container Images
Step-by-Step Implementation
-
Generate the Docker Registry Secret:
BASHkubectl create secret docker-registry private-hub-sec \ --docker-server=https://index.docker.io/v1/ \ --docker-username=myuser \ --docker-password=mypassword \ --docker-email=user@example.com -
Reference the Secret in the Pod Manifest (
imagePullSecrets):YAMLapiVersion: v1 kind: Pod metadata: name: private-image-pod spec: containers: - name: private-app image: myuser/private-repo:v1.0.0 imagePullSecrets: - name: private-hub-sec
8. Production Secret Management Frameworks
Because storing Base64-encoded Kubernetes Secrets in Git repositories violates GitOps practices, production enterprise clusters utilize external secret management operators and Container Storage Interface (CSI) drivers.
Enterprise Secret Architectures Compared
Vault Integration Flow with CSI Driver
Container Pod
|
| (1) Requests Volume Mount via SecretProviderClass
v
Secret Store CSI Driver
|
| (2) Authenticates via Service Account Token
v
HashiCorp Vault / External KMS
|
| (3) Returns Encrypted Secrets Stream
v
In-Memory Volume (tmpfs mounted inside Container)
9. Real-World Debugging & Common Edge Cases
Edge Case 1: Missing ConfigMap or Secret at Startup
If a container references a configMapKeyRef or secretKeyRef that does not exist or has a misspelled key, the Pod will stall during container creation.
- Status:
CreateContainerConfigErrororCreateContainerError - Diagnosis Workflow:
Output Error snippet:BASH
# Check events for exact failure reasons kubectl describe pod <pod-name>Error: configmap "bootcamp-config" not found - Resolution: Mark the key as optional if runtime availability is non-blocking:
YAML
valueFrom: configMapKeyRef: name: optional-config key: log_level optional: true
Edge Case 2: Volume Mount Overwrites Target Directory
If you mount a ConfigMap or Secret to a directory like /etc without specifying a subPath, Kubernetes will obscure the entire existing contents of /etc with the mounted secret files.
# DANGEROUS: Replaces the target folder contents entirely
volumeMounts:
- name: my-secret-vol
mountPath: /etc # Overwrites host container /etc folder!
# SAFE: Mounts specific key without wiping existing files
volumeMounts:
- name: my-secret-vol
mountPath: /etc/app-config.json
subPath: app-config.json
Edge Case 3: Trailing Newlines in Base64 Encoding
Using standard echo without the -n flag appends a hidden newline character (\n) to your string before encoding it. This breaks database passwords and API tokens.
# WRONG (Includes hidden \n character):
echo "my-password" | base64
# Yields: bXktcGFzc3dvcmQK (Decodes to "my-password\n")
# CORRECT:
echo -n "my-password" | base64
# Yields: bXktcGFzc3dvcmQ= (Decodes to "my-password")
Summary and Key Takeaways
- Decoupling Application State: ConfigMaps handle non-confidential operational variables (URLs, tuning parameters), whereas Secrets isolate confidential data (passwords, tokens, private keys).
- Base64 Encoding Reality: Standard Kubernetes Secrets are Base64 encoded by default, not encrypted. Access to
etcdor read privileges on Secret APIs exposes all values in plain text. - 4 Ingestion Vectors: Both ConfigMaps and Secrets can be exposed as environment variables, command-line arguments, filesystem volume mounts, or programmatically via the Kubernetes API.
- Volume Mount Dynamics: Mounting a ConfigMap or Secret as a volume updates dynamically when changed in the cluster, whereas environment variables require a Pod restart to reflect updates.
- Immutability Performance Optimization: Marking ConfigMaps and Secrets as
immutable: trueprevents accidental edits and removes polling overhead fromkubelet, improving cluster scalability. - Authenticating Image Pulls: Pulling container images from private registries requires a Secret of type
kubernetes.io/dockerconfigjsonbound to the Pod spec viaimagePullSecrets. - GitOps & Production Hardening: Store plain-text secrets out of source control. Use enterprise integrations like Sealed Secrets, External Secrets Operator (ESO), or Secrets Store CSI Driver (with HashiCorp Vault or Cloud KMS) for GitOps workflows.
- SubPath Precision: When mounting individual configuration files, utilize
subPathdefinitions withinvolumeMountsto prevent accidentally overwriting entire container destination directories.