You don't want to rebuild the image to change a URL. ConfigMap and Secret exist to separate configuration from code.
But there is a dangerous difference between “working” and “being secure”. A Secret with minioadmin already brought down a deployment of ours — and the guard was right.
Course seal: tested on Kubernetes 1.35.
ConfigMap: non-sensitive configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_ENV: production
LOG_LEVEL: info
features.json: |
{"novoCheckout": true}
Three ways to consume:
# 1) individual variable
env:
- name: APP_ENV
valueFrom:
configMapKeyRef:
name: app-config
key: APP_ENV
# 2) all keys as variables
envFrom:
- configMapRef:
name: app-config
# 3) mounted file
volumes:
- name: config
configMap:
name: app-config
Secret: sensitive configuration (with caveats)
kubectl create secret generic app-secret \
--from-literal=DB_PASSWORD='...' \
--from-literal=API_TOKEN='...'
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secret
key: DB_PASSWORD
Base64 is not encryption. Anyone with get secret sees the value. Secret security depends on:
- Restrictive RBAC.
- Etcd encryption at rest.
- Not versioning secrets in Git.
- Rotation.
ConfigMap/Secret in volume
Mounting as a file:
volumes:
- name: secret
secret:
secretName: app-secret
Each key becomes a file. Updates to the ConfigMap/Secret propagate to the volume (with delay), but not to already injected environment variables. If the application reads env at boot, it needs to restart.
immutable: true prevents changes and reduces load on the kubelet; useful for versioned configurations.
The credentials guard
A production guard checks if known default passwords are in use. Real example:
INF-SEC-01: default credentials/missing secret detected in production
(app.storage.s3.accessKey, app.storage.s3.secretKey).
The app refused to start because the secret had minioadmin. The guard was right; the cluster was wrong.
Practical lesson: preflight in the pipeline. Before changing the image:
VAL=$(kubectl -n portal get secret portal-secrets \
-o jsonpath='{.data.APP_STORAGE_S3_ACCESSKEY}' | base64 -d)
[ "$VAL" != "minioadmin" ] || { echo "default credential"; exit 1; }
Rotation without downtime
- Create the new credential in the provider (MinIO, database, API).
- Update the Secret.
- Restart the pods that read env (rolling update).
- Validate.
- Revoke the old one.
For secrets that cannot coexist, plan a window. For those that support multiple keys, do gradual rotation.
Alternatives to native Secret
| Tool | Idea |
|---|---|
| Sealed Secrets | encrypted secret in Git |
| External Secrets Operator | fetches from Vault/AWS/GCP |
| SOPS | encryption in the repository |
| Vault Agent Injector | injects secret at runtime |
The goal is the same: the real value is not stored in plain text in Git.
Lab
- Create ConfigMap and Secret.
- Inject as env and as volume.
- Change the ConfigMap and see the file update (and the env not).
- Try to start a pod with
secretKeyReffor a non-existent key — see the error. - Decode the Secret and prove that base64 does not protect.
Common errors
| Symptom | Cause |
|---|---|
CreateContainerConfigError |
missing Secret/ConfigMap key |
| App doesn't see change | env injected at boot; needs restart |
illegal base64 data |
invalid value in Secret |
File with \r |
CRLF in the value |
| Secret in Git | leak; rotate |
| Guard brings down the pod | default credential in production |
Checklist
- [ ] Non-sensitive configuration in ConfigMap.
- [ ] Secrets in Secret with restrictive RBAC.
- [ ] Etcd with encryption at rest.
- [ ] No secrets in plain text in Git.
- [ ] Documented rotation plan.
- [ ] Credentials preflight in the pipeline.
- [ ] I know that base64 is not encryption.
Glossary
- ConfigMap: non-sensitive configuration.
- Secret: object for sensitive data.
- envFrom: imports all keys as env.
- immutable: immutable object.
- External Secrets: operator that synchronizes external secrets.
- etcd encryption: encryption of state at rest.
Next
Now that configuration is under control, let's observe the cluster: metrics-server, Prometheus, Grafana, and the signals that really matter.
Next: Kubernetes Course 13 — Observability: metrics-server, Prometheus, and Grafana
Keep reading
Read also

StorCLI - Complete Cheat Sheet
StorCLI is the official and modern tool for managing Broadcom/LSI RAID controllers. This guide covers essential commands, syntax and use cases.
12 min de leitura
Portal ITSMBusiness Services in Nyverra Portal: Translating IT into Business
The business doesn't feel a server go down — it feels email stop. The Business Services (Service Mapping) module of Nyverra ITSM Portal connects services like Email, ERP or PACS to CMDB assets, revealing the real impact of each failure.
5 min de leitura
SegurançaRPO vs RTO: How to Define Before Buying Backup (and Why Most Companies Get It Wrong)
Most companies buy backup asking the wrong question: "how much does it cost?". The right question is: how much data can I lose (RPO) and how long can I be down (RTO). Discover how to define these numbers per system and avoid purchasing protection based on price, not on real need.
9 min de leitura
Comments
No comments yet
Be the first to share your thoughts on this article.

Leave a comment