Env vars. After quite some time hacking servers, bash, and Docker, I’ve came to terms with them. They’re simple and useful.
But being a raw UNIX construct from 1979, env vars are not that manageable today. Just look at a command like this:
AWS_KEY_ID=xxxxx AWS_SECRET_KEY=xxxxx USER=XXXX
CPU_POOLING=0.5 DEBUG_MODE=on
VERBOSITY_LEVEL=ALL <program>
If you type that once, that’s fine. But repeatedly entering such commands becomes a major pain rather quickly.
What about config files?
Sure, in many situations we can use yaml
, json
, toml
, or even dhall. But not always. Sometimes, you just have a simple program or a 3rd party CLI that accepts env vars and isn’t hackable. For instance – terraform
, heroku
(and many others), are amazing tools that make good use of env vars, but you don’t have the luxury of injecting a .json
config file when you run them.
Hello .env
To improve the situation, we’ve invented .env
– a simple way of storing storing env vars in a hidden file. Every major programming language probably has a parser for these today. And that’s great – it means we’re getting cleaner, more ops-friendly apps, better aligned with the 12 factor approach.
But I’ve been missing something. Sometimes I have multiple scripts and tools in a project, and despite the fact that the main program might be a modern scripting language (node, python) where I can easily inject .env
, many tools simply can’t do that (binaries).
Hacking shell – envo
So I’ve made envo
– a simple shell script that parses .env
file and injects env vars to any CLI command.
For example:
Usage examples:
envo yarn run command
envo -f /path/to/custom/.env terraform apply
envo -e VAR1=VAL1 -e VAR2=VAL2 node app.js
There are ways to do it with a bash oneliner:
export (cat .env | xargs) && cmd
But there are several issues with the above:
- Doesn’t work in some non-standard shells (I’m using fish)
- Not that user-friendly and easy to write (using
xargs
is not that straightforward)
Usage examples
1) Private NPM
When working with private NPM packages, you have to use .npmrc
file to store authentication token to access your packages. Without a valid token, any yarn ..
command is going to fail.
You would create .npmrc
file with //registry.npmjs.org/:_authToken=XX_TOKEN_XX
. But then, you might also have a .env
file. Now every new developer on the project needs get a copy of 2 files with secrets.
Instead, you can put NPM_TOKEN=XX_TOKEN_XX
into your .env
file, and use template in .npmrc
like this //registry.npmjs.org/:_authToken=${NPM_TOKEN}
. Now you have only a single secrets file, (you can now track .npmrc
in git, and you run envo yarn
.
2) Terraform & AWS
To use terraform
with AWS
, you need AWS credentials. By default, terraform checks $HOME/.aws/credentials
, but if you have multiple AWS accounts, this quickly gets out of hand.
Instead, you can pass your AWS_ACCESS_KEY_ID
, AWS_SECRET_ACCESS_KEY
, AWS_DEFAULT_REGION
env vars (or export them) with every terraform command. But if you do it frequently, you need to store these secrets somewhere.
With envo
you can just put these into .env
file:
AWS_ACCESS_KEY_ID="anaccesskey"
AWS_SECRET_ACCESS_KEY="asecretkey"
AWS_DEFAULT_REGION="us-west-2"
and then just run envo terraform apply
Install
Just type this to install on your machine:
curl https://raw.githubusercontent.com/awinecki/envo/main/envo --output ~/.local/bin/envo && chmod +x ~/.local/bin/envo
You can also install it locally in a single project like this:
curl https://raw.githubusercontent.com/awinecki/envo/main/envo --output envo.sh && chmod +x envo.sh
(remember to use it with ./envo.sh
in this scenario)
It’s not working!
If you intend to use this in production, do so at your own risk. Although it’s tested, there are better ways to manage env variables in production environments (k8s secrets, swarm secrets, hashicorp vault).
If you encounter any problem, submit issue in the Github repository.
Happy hacking! 🤞