A credential in .env
A value that must become a Secret rather than a ConfigMap, detected by name
DB_PASSWORD=hunter2 DEBUG=true API_URL=https://api.example.com
Paste a .env file and get a ConfigMap and a Secret, with the credentials separated out and the keys that will not survive envFrom named. It runs in this tab, which is the only sane place to paste a file full of passwords.
Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.
The answer appears here
Paste on the left and press Convert. Nothing leaves this tab.
Nothing else to flag.
No formatting problems, and nothing the rules object to. Worth remembering what that covers: this reads the file you pasted, not the account or cluster it will be applied to.
No finding matches that filter.
Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.
A value that must become a Secret rather than a ConfigMap, detected by name
DB_PASSWORD=hunter2 DEBUG=true API_URL=https://api.example.com
Quotes, spaces and a dollar sign, none of which Kubernetes interpolates
GREETING="hello world" PATH_PREFIX=/api/v1 COST=$100 EMPTY=
These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.
ConfigMaps are not access-controlled the way Secrets are, are readable by anyone with get in the namespace, and appear in kubectl describe output in full.
Instead:Split the file: non-secret values to a ConfigMap, credentials to a Secret.
Docker Compose, dotenv libraries and shells all differ on quotes, escapes and interpolation. Kubernetes does none of it: the value is literal.
Instead:Check any value containing quotes, spaces or a dollar sign after conversion.
Values injected with envFrom are read at container start. Editing the ConfigMap does nothing until the pod restarts, unlike a mounted volume which updates eventually.
Instead:Restart the workload, or mount as a volume if live updates matter.
The conversion is four lines of sed. What is not is everything that goes wrong after the ConfigMap is applied and appears to have worked.
envFrom turns every key in a ConfigMap into an environment variable, and a variable name has to match [A-Za-z_][A-Za-z0-9_]*. A key with a dot or a dash in it does not, so the kubelet skips it, writes an InvalidVariableNames event nobody reads, and starts the container anyway. The application sees the variable as unset and falls back to a default. Spring and Symfony .env files are full of dotted keys.
Keys and values that look like credentials go into a Secret and the rest into a ConfigMap, with the reason for each move reported. A ConfigMap is readable by anything with get on ConfigMaps in the namespace and is dumped by default in most debug tooling, so the split is worth making at conversion time rather than never.
ConfigMap and Secret data are both string maps. PORT=8080 written unquoted becomes a YAML integer and the API server rejects the object with a Go unmarshalling error that never names the key. So does DEBUG=true, and so does anything YAML reads as a boolean, which includes no, off and y. Every value in the output is quoted, so the whole class is gone.
Escape sequences are interpreted inside double quotes and not inside single ones, which is what makes single quotes right for Windows paths. An unquoted hash starts a comment and a quoted one does not. Multi-line quoted values, which is how a PEM key ends up in a .env, are read to their closing quote and emitted as a block scalar.
A .env file is read by the application at startup. A ConfigMap is read by the kubelet, at container start, and the difference in when and how often matters more than the difference in format.
envFrom is the direct equivalent of an .env file and is what most people want. It is also where the silent key-skipping happens. Referencing a key explicitly with configMapKeyRef has no naming restriction at all, so it is the escape hatch for a key you cannot rename.
envFrom: # every key, names unchanged
- configMapRef:
name: app-config
- secretRef:
name: app-secrets
env: # one key, renamed on the way
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: app-config
key: spring.datasource.url # dots are fine here This is the single most surprising part. A ConfigMap consumed through env or envFrom is read once, when the container starts. Edit it afterwards and every running pod keeps the old values indefinitely, because nothing triggers a restart. Mounted as a volume it does update in place, after a delay of up to the kubelet sync period, but the process still has to notice the file changed.
kubectl edit configmap app-config # takes effect: never
kubectl rollout restart deploy/api # takes effect: now
# or make the change force a rollout, by putting a hash
# of the config in the pod template annotations Secret data is base64, which is an encoding. Anyone who can read the Secret can read the value, and by default that is anyone with get on Secrets in the namespace, plus every ServiceAccount token that grants it. What actually protects a Secret is RBAC, and encryption at rest if the cluster has it turned on. Neither of those is a property of the file this tool gives you.
# what is in the manifest either way:
stringData:
DB_PASSWORD: hunter2 <- plain text
data:
DB_PASSWORD: aHVudGVyMg== <- also plain text,
with extra steps
# so do not commit either. Sealed Secrets, the External
# Secrets Operator and SOPS all exist for this. Before the container starts, Kubernetes substitutes $(OTHER_VAR) in env values using the other variables in the same container. A password containing that sequence is rewritten, and if the name does not resolve the text is left alone, so the same value behaves differently depending on what else happens to be set.
PASSWORD=abc$(def)ghi
-> if DEF is set: abc<value of DEF>ghi
-> if it is not: abc$(def)ghi
escape it as $$(, or mount the value as a file,
where no substitution happens at all