avatar-andy

Streamline Environment Variables CLI Usage with envo

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:

envo demo
Example `envo` usage

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:

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! 🤞