12. ConfigMap and Secret#
flowchart LR
CM[ConfigMap] -->|env vars| Pod[Pod]
CM -->|volume mount| Pod
Sec[Secret] -->|env vars| Pod
Sec -->|volume mount| Pod
ESO[External Secrets<br/>Operator] -->|sync| Sec
Vault[(HashiCorp Vault)] --> ESO
ConfigMap#
Creation#
# From literal values
kubectl create configmap app-config \
--from-literal=DB_HOST=mysql-svc \
--from-literal=DB_PORT=3306 \
--from-literal=LOG_LEVEL=info
# From file
kubectl create configmap nginx-config --from-file=nginx.conf
# From directory
kubectl create configmap configs --from-file=./config-dir/
# From env file
kubectl create configmap app-env --from-env-file=.env
ConfigMap YAML#
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DB_HOST: "mysql-svc"
DB_PORT: "3306"
LOG_LEVEL: "info"
# Multi-line config file
app.properties: |
server.port=8080
spring.datasource.url=jdbc:mysql://mysql-svc:3306/mydb
logging.level.root=INFO
Using ConfigMap as Environment Variables#
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: app
image: myapp:1.0
# Individual keys
env:
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: DB_HOST
# All keys as env vars
envFrom:
- configMapRef:
name: app-config
prefix: APP_ # optional prefix
Using ConfigMap as Volume#
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: app
image: myapp:1.0
volumeMounts:
- name: config
mountPath: /etc/app
readOnly: true
- name: nginx-config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf # mount single file
volumes:
- name: config
configMap:
name: app-config
- name: nginx-config
configMap:
name: nginx-config
Secret#
Secret Types#
Type |
Usage |
|---|---|
|
Arbitrary key-value data (default) |
|
Docker registry credentials |
|
TLS certificate and key |
|
Basic authentication |
|
SSH private key |
Creation#
# Opaque secret
kubectl create secret generic db-secret \
--from-literal=username=admin \
--from-literal=password='s3cret!'
# Docker registry secret
kubectl create secret docker-registry regcred \
--docker-server=registry.example.com \
--docker-username=user \
--docker-password=pass
# TLS secret
kubectl create secret tls tls-secret \
--cert=tls.crt \
--key=tls.key
# From file
kubectl create secret generic ssh-key --from-file=ssh-privatekey=~/.ssh/id_rsa
Secret YAML#
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
# base64 encoded: echo -n 'admin' | base64
username: YWRtaW4=
password: czNjcmV0IQ==
---
# Using stringData (plain text, auto-encoded)
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
stringData:
username: admin
password: "s3cret!"
Using Secrets#
spec:
containers:
- name: app
image: myapp:1.0
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
volumeMounts:
- name: tls
mountPath: /etc/tls
readOnly: true
volumes:
- name: tls
secret:
secretName: tls-secret
imagePullSecrets:
- name: regcred
Immutable ConfigMaps and Secrets#
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config-v2
immutable: true # cannot be updated, must create new version
data:
DB_HOST: "mysql-svc"
Benefits: protects against accidental updates, improves performance (kubelet doesn’t watch for changes).
External Secrets Management#
Sealed Secrets#
# Install sealed-secrets controller
helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm install sealed-secrets sealed-secrets/sealed-secrets -n kube-system
# Install kubeseal CLI
brew install kubeseal
# Seal a secret
kubectl create secret generic db-secret \
--from-literal=password=s3cret --dry-run=client -o yaml | \
kubeseal --format yaml > sealed-secret.yaml
# Apply sealed secret (safe to commit to git)
kubectl apply -f sealed-secret.yaml
External Secrets Operator#
# Install
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets -n external-secrets --create-namespace
# SecretStore (connects to Vault)
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-store
spec:
provider:
vault:
server: "https://vault.example.com"
path: "secret"
auth:
kubernetes:
mountPath: "kubernetes"
role: "myapp"
---
# ExternalSecret (syncs from Vault to K8s Secret)
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-secret
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-store
kind: SecretStore
target:
name: db-secret
data:
- secretKey: password
remoteRef:
key: myapp/database
property: password