Kubernetes_configmaps_secrets
Chapter 22: Kubernetes ConfigMaps and Secrets - Configuration Management
Section titled “Chapter 22: Kubernetes ConfigMaps and Secrets - Configuration Management”Table of Contents
Section titled “Table of Contents”- Introduction to Configuration Management
- What is a ConfigMap?
- Creating ConfigMaps
- Using ConfigMaps in Pods
- What is a Secret?
- Creating Secrets
- Using Secrets in Pods
- Best Practices
- Hands-on Lab
- Summary
Introduction to Configuration Management
Section titled “Introduction to Configuration Management”The Configuration Challenge
Section titled “The Configuration Challenge”In containerized applications, we need to separate configuration from code. This allows the same container image to run in different environments (dev, staging, production) with different configurations.
┌─────────────────────────────────────────────────────────────────────────────┐│ CONFIGURATION MANAGEMENT CHALLENGE │├─────────────────────────────────────────────────────────────────────────────┤│ ││ Problem: Different environments need different configs ││ ───────────────────────────────────────────────────── ││ ││ ┌─────────────────────────────────────────────────────────────────────┐ ││ │ CONTAINER IMAGE │ ││ │ (Same for all environments) │ ││ │ │ ││ │ myapp:v1.0 │ ││ │ │ ││ └─────────────────────────────────────────────────────────────────────┘ ││ │ │ │ ││ ▼ ▼ ▼ ││ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ││ │ DEV │ │ STAGING │ │ PRODUCTION │ ││ │ │ │ │ │ │ ││ │ DB: localhost│ │ DB: staging │ │ DB: prod-db │ ││ │ DEBUG: true │ │ DEBUG: true │ │ DEBUG: false│ ││ │ LOG: verbose │ │ LOG: info │ │ LOG: error │ ││ │ PORT: 3000 │ │ PORT: 8080 │ │ PORT: 80 │ ││ └──────────────┘ └──────────────┘ └──────────────┘ ││ ││ Solution: Externalize configuration using ConfigMaps and Secrets ││ │└─────────────────────────────────────────────────────────────────────────────┘What is a ConfigMap?
Section titled “What is a ConfigMap?”ConfigMap Overview
Section titled “ConfigMap Overview”A ConfigMap is a Kubernetes resource used to store non-sensitive configuration data in key-value pairs. Pods can consume ConfigMaps as environment variables, command-line arguments, or configuration files in volumes.
┌─────────────────────────────────────────────────────────────────────────────┐│ CONFIGMAP CONCEPT │├─────────────────────────────────────────────────────────────────────────────┤│ ││ ┌───────────────────────────────────────────────────────────────────┐ ││ │ CONFIGMAP │ ││ │ metadata: │ ││ │ name: app-config │ ││ │ │ ││ │ data: │ ││ │ database_url: postgres://db:5432/mydb │ ││ │ cache_enabled: "true" │ ││ │ log_level: info │ ││ │ config.json: | │ ││ │ { │ ││ │ "timeout": 30, │ ││ │ "retries": 3 │ ││ │ } │ ││ │ │ ││ └───────────────────────────────────────────────────────────────────┘ ││ │ ││ ▼ ││ ┌───────────────────────────────────────────────────────────────────┐ ││ │ POD │ ││ │ │ ││ │ Environment Variables: │ ││ │ ├── DATABASE_URL=postgres://db:5432/mydb │ ││ │ ├── CACHE_ENABLED=true │ ││ │ └── LOG_LEVEL=info │ ││ │ │ ││ │ Files (mounted): │ ││ │ └── /etc/config/config.json │ ││ │ { │ ││ │ "timeout": 30, │ ││ │ "retries": 3 │ ││ │ } │ ││ │ │ ││ └───────────────────────────────────────────────────────────────────┘ ││ │└─────────────────────────────────────────────────────────────────────────────┘Creating ConfigMaps
Section titled “Creating ConfigMaps”From Literal Values
Section titled “From Literal Values”# Create ConfigMap from literal key-value pairskubectl create configmap app-config \ --from-literal=database_url=postgres://db:5432/mydb \ --from-literal=cache_enabled=true \ --from-literal=log_level=infoFrom Files
Section titled “From Files”# Create from a filekubectl create configmap app-config-file \ --from-file=config.json
# Create from multiple fileskubectl create configmap app-multiple-files \ --from-file=app.properties \ --from-file=db.propertiesFrom Environment Variables
Section titled “From Environment Variables”# Create from .env filekubectl create configmap app-env \ --from-env-file=.envFrom YAML
Section titled “From YAML”apiVersion: v1kind: ConfigMapmetadata: name: app-configdata: # Simple key-value database_url: "postgres://db:5432/mydb" cache_enabled: "true" log_level: "info"
# Configuration file as value config.json: | { "timeout": 30, "retries": 3, "maxConnections": 100 }
# Properties file format application.properties: | spring.datasource.url=postgres://db:5432/mydb spring.datasource.username=admin server.port=8080# Apply ConfigMapkubectl apply -f configmap.yamlUsing ConfigMaps in Pods
Section titled “Using ConfigMaps in Pods”As Environment Variables
Section titled “As Environment Variables”apiVersion: v1kind: Podmetadata: name: myapp-podspec: containers: - name: myapp image: myapp:latest env: # Simple environment variable - name: DATABASE_URL valueFrom: configMapKeyRef: name: app-config key: database_url # All configmap values as env vars envFrom: - configMapRef: name: app-config # With default value - name: CACHE_ENABLED valueFrom: configMapKeyRef: name: app-config key: cache_enabled optional: true # Won't fail if missingAs Volume Mount
Section titled “As Volume Mount”apiVersion: v1kind: Podmetadata: name: myapp-podspec: containers: - name: myapp image: myapp:latest volumeMounts: - name: config-volume mountPath: /etc/config readOnly: true volumes: - name: config-volume configMap: name: app-config # Optional: specific keys # items: # - key: config.json # path: app-config.jsonHow It Works
Section titled “How It Works”┌─────────────────────────────────────────────────────────────────────────────┐│ CONFIGMAP USAGE METHODS │├─────────────────────────────────────────────────────────────────────────────┤│ ││ Method 1: Environment Variables ││ ───────────────────────────────────── ││ pod.spec.containers[].env: ││ ┌─────────────────────────────────────────────────────────────────────┐ ││ │ - name: DATABASE_URL │ ││ │ valueFrom: │ ││ │ configMapKeyRef: │ ││ │ name: app-config │ ││ │ key: database_url │ ││ └─────────────────────────────────────────────────────────────────────┘ ││ Result: DATABASE_URL=postgres://db:5432/mydb ││ ││ Method 2: All env vars at once ││ ───────────────────────────────────── ││ pod.spec.containers[].envFrom: ││ ┌─────────────────────────────────────────────────────────────────────┐ ││ │ - configMapRef: │ ││ │ name: app-config │ ││ └─────────────────────────────────────────────────────────────────────┘ ││ Result: All keys become env vars ││ ││ Method 3: Volume Mount ││ ───────────────────── ││ pod.spec.volumes[]: ││ ┌─────────────────────────────────────────────────────────────────────┐ ││ │ - name: config │ ││ │ configMap: │ ││ │ name: app-config │ ││ └─────────────────────────────────────────────────────────────────────┘ ││ Result: Files in /etc/config/ ││ │└─────────────────────────────────────────────────────────────────────────────┘What is a Secret?
Section titled “What is a Secret?”Secret Overview
Section titled “Secret Overview”A Secret is similar to a ConfigMap but is intended to hold small amounts of sensitive data such as passwords, OAuth tokens, and SSH keys. Secrets are stored encoded (base64) by default and can be encrypted at rest.
┌─────────────────────────────────────────────────────────────────────────────┐│ SECRET CONCEPT │├─────────────────────────────────────────────────────────────────────────────┤│ ││ ┌───────────────────────────────────────────────────────────────────┐ ││ │ SECRET │ ││ │ metadata: │ ││ │ name: db-credentials │ ││ │ │ ││ │ data: │ ││ │ username: YWRtaW4= # "admin" base64 encoded │ ││ │ password: cGFzc3dvcmQ= # "password" base64 encoded │ ││ │ │ ││ │ stringData: # Plain text (auto-encoded) │ ││ │ api-key: my-api-key-12345 │ ││ │ │ ││ └───────────────────────────────────────────────────────────────────┘ ││ │ ││ ▼ ││ ┌───────────────────────────────────────────────────────────────────┐ ││ │ POD │ ││ │ │ ││ │ Environment Variables (decoded): │ ││ │ ├── DB_USERNAME=admin │ ││ │ └── DB_PASSWORD=password │ ││ │ │ ││ │ Files (mounted, decoded): │ ││ │ └── /etc/secret/db-credentials/username │ ││ │ └── /etc/secret/db-credentials/password │ ││ │ │ ││ └───────────────────────────────────────────────────────────────────┘ ││ ││ Security Note: ││ • Base64 is NOT encryption - anyone can decode ││ • Enable encryption at rest for real security ││ • Use RBAC to restrict Secret access ││ │└─────────────────────────────────────────────────────────────────────────────┘Creating Secrets
Section titled “Creating Secrets”From Literal Values
Section titled “From Literal Values”# Create secret from literalskubectl create secret generic db-credentials \ --from-literal=username=admin \ --from-literal=password=secretpasswordFrom Files
Section titled “From Files”# Create secret from file (for certificates, keys)kubectl create secret tls my-tls-secret \ --cert=path/to/cert.crt \ --key=path/to/key.key
# Create docker registry secretkubectl create secret docker-registry my-registry-secret \ --docker-username=admin \ --docker-password=secret \ --docker-email=admin@example.comFrom YAML
Section titled “From YAML”apiVersion: v1kind: Secretmetadata: name: db-credentialstype: Opaque # Generic secretdata: # Base64 encoded values username: YWRtaW4= password: cGFzc3dvcmQ=---apiVersion: v1kind: Secretmetadata: name: api-keytype: OpaquestringData: # Plain text (will be base64 encoded) api-key: my-api-key-12345# Apply secretkubectl apply -f secret.yamlSecret Types
Section titled “Secret Types”┌─────────────────────────────────────────────────────────────────────────────┐│ SECRET TYPES │├─────────────────────────────────────────────────────────────────────────────┤│ ││ Type │ Use Case ││ ────────────────────┼───────────────────── ││ Opaque │ Generic key-value pairs (default) ││ kubernetes.io/tls │ TLS certificates and keys ││ kubernetes.io/dockerconfigjson │ Docker registry credentials ││ kubernetes.io/basic-auth │ Basic authentication ││ kubernetes.io/ssh-auth │ SSH credentials ││ kubernetes.io/token │ Service account tokens ││ ││ Examples: ││ ┌────────────────────────────────────────────────────────────────────┐ ││ │ # TLS Secret │ ││ │ apiVersion: v1 │ ││ │ kind: Secret │ ││ │ type: kubernetes.io/tls │ ││ │ metadata: │ ││ │ name: my-tls │ ││ │ data: │ ││ │ tls.crt: <base64 cert> │ ││ │ tls.key: <base64 key> │ ││ └────────────────────────────────────────────────────────────────────┘ ││ ││ ┌────────────────────────────────────────────────────────────────────┐ ││ │ # Docker Registry Secret │ ││ │ apiVersion: v1 │ ││ │ kind: Secret │ ││ │ type: kubernetes.io/dockerconfigjson │ ││ │ metadata: │ ││ │ name: my-registry │ ││ │ data: │ ││ │ .dockerconfigjson: <base64 config> │ ││ └────────────────────────────────────────────────────────────────────┘ ││ │└─────────────────────────────────────────────────────────────────────────────┘Using Secrets in Pods
Section titled “Using Secrets in Pods”As Environment Variables
Section titled “As Environment Variables”apiVersion: v1kind: Podmetadata: name: myapp-podspec: containers: - name: myapp image: myapp:latest env: - name: DB_USERNAME valueFrom: secretKeyRef: name: db-credentials key: username - name: DB_PASSWORD valueFrom: secretKeyRef: name: db-credentials key: password # All secret values as env vars envFrom: - secretRef: name: api-keyAs Volume Mount
Section titled “As Volume Mount”apiVersion: v1kind: Podmetadata: name: myapp-podspec: containers: - name: myapp image: myapp:latest volumeMounts: - name: secret-volume mountPath: "/etc/secret" readOnly: true volumes: - name: secret-volume secret: secretName: db-credentials # Optional: specific keys # items: # - key: username # path: db-userImage Pull Secret
Section titled “Image Pull Secret”apiVersion: v1kind: Podmetadata: name: myapp-podspec: containers: - name: myapp image: myregistry.io/myapp:latest imagePullSecrets: - name: my-registry-secretBest Practices
Section titled “Best Practices”Configuration Best Practices
Section titled “Configuration Best Practices”┌─────────────────────────────────────────────────────────────────────────────┐│ BEST PRACTICES │├─────────────────────────────────────────────────────────────────────────────┤│ ││ ConfigMaps: ││ ─────────── ││ ✓ Use ConfigMaps for non-sensitive configuration ││ ✓ Version your ConfigMaps ││ ✓ Use descriptive names ││ ✓ Group related configs in same ConfigMap ││ ✓ Use different ConfigMaps per environment ││ ││ Secrets: ││ ──────── ││ ✓ Enable encryption at rest ││ ✓ Use RBAC to restrict access ││ ✓ Rotate secrets regularly ││ ✓ Don't commit secrets to version control ││ ✓ Use external secrets management (Vault, AWS Secrets Manager) ││ ││ General: ││ ──────── ││ ✓ Use the same ConfigMap/Secret across environments ││ ✓ Don't hardcode values in applications ││ ✓ Use volume mounts for files, env vars for strings ││ ✓ Monitor for configuration drift ││ ││ Encryption at Rest: ││ ───────────────── ││ Enable in kube-apiserver: ││ --encryption-provider-config=/path/to/encryption.yaml ││ ││ encryption.yaml: ││ ┌───────────────────────────────────────────────────────────────────┐ ││ │ apiVersion: v1 │ ││ │ kind: EncryptionConfiguration │ ││ │ resources: │ ││ │ - resources: │ ││ │ - secrets │ ││ │ providers: │ ││ │ - aescbc: │ ││ │ keys: │ ││ │ - name: key1 │ ││ │ secret: <base64 32-byte key> │ ││ └───────────────────────────────────────────────────────────────────┘ ││ │└─────────────────────────────────────────────────────────────────────────────┘Hands-on Lab
Section titled “Hands-on Lab”Lab: Using ConfigMaps and Secrets
Section titled “Lab: Using ConfigMaps and Secrets”In this hands-on lab, we’ll create and use ConfigMaps and Secrets.
Prerequisites
Section titled “Prerequisites”- A running Kubernetes cluster
Lab Steps
Section titled “Lab Steps”# Step 1: Create a ConfigMap from literal valueskubectl create configmap app-config \ --from-literal=database_url=postgres://localhost:5432/mydb \ --from-literal=log_level=info
# Step 2: Create a ConfigMap from a filecat > config.json << 'EOF'{ "timeout": 30, "retries": 3, "cache": { "enabled": true, "ttl": 3600 }}EOF
kubectl create configmap app-config-file \ --from-file=config.json
# Step 3: Verify ConfigMapskubectl get configmapkubectl describe configmap app-config
# Step 4: Create a Secretkubectl create secret generic db-credentials \ --from-literal=username=admin \ --from-literal=password=secret123
# Step 5: Verify Secretkubectl get secretkubectl describe secret db-credentials
# Decode secret valuekubectl get secret db-credentials -o jsonpath='{.data.password}' | base64 -d
# Step 6: Create a Pod using ConfigMap and Secretcat > pod-with-config.yaml << 'EOF'apiVersion: v1kind: Podmetadata: name: myapp-podspec: containers: - name: myapp image: nginx:latest env: - name: DATABASE_URL valueFrom: configMapKeyRef: name: app-config key: database_url - name: DB_USERNAME valueFrom: secretKeyRef: name: db-credentials key: username - name: DB_PASSWORD valueFrom: secretKeyRef: name: db-credentials key: password volumeMounts: - name: config-volume mountPath: /etc/config volumes: - name: config-volume configMap: name: app-config-fileEOF
kubectl apply -f pod-with-config.yaml
# Step 7: Verify pod has the valueskubectl exec myapp-pod -- env | grep -E "(DATABASE_URL|DB_)"kubectl exec myapp-pod -- ls -la /etc/config/
# Step 8: Clean upkubectl delete pod myapp-podkubectl delete configmap app-config app-config-filekubectl delete secret db-credentialsSummary
Section titled “Summary”Key Takeaways
Section titled “Key Takeaways”- ConfigMaps - Store non-sensitive configuration data
- Secrets - Store sensitive data (base64 encoded)
- Usage Methods - Environment variables or volume mounts
- Best Practices - Encryption at rest, RBAC, external secrets management
Quick Reference
Section titled “Quick Reference”# Create ConfigMapkubectl create configmap my-config --from-literal=key=valuekubectl create configmap my-config --from-file=config.json
# Create Secretkubectl create secret generic my-secret --from-literal=key=value
# Use in Pod# env:# - name: KEY# valueFrom:# configMapKeyRef:# name: my-config# key: key
# volumeMounts:# - name: config# mountPath: /etc/config# volumes:# - name: config# configMap:# name: my-configNext Steps
Section titled “Next Steps”In the next chapter, we’ll explore Kubernetes Storage (Chapter 23), covering:
- PersistentVolumes
- PersistentVolumeClaims
- StorageClasses