Skip to content

Commit

Permalink
Merge pull request #79 from cli-guidelines/no-secret-envs
Browse files Browse the repository at this point in the history
  • Loading branch information
tashian committed Apr 13, 2021
2 parents 8b83889 + 706ad1f commit ce86821
Showing 1 changed file with 29 additions and 19 deletions.
48 changes: 29 additions & 19 deletions content/_index.md
Expand Up @@ -806,17 +806,16 @@ unknown flag: --foo
This can be very confusing for the user—especially given that one of the most common things users do when trying to get a command to work is to hit the up arrow to get the last invocation, stick another option on the end, and run it again.
If possible, try to make both forms equivalent, although you might run up against the limitations of your argument parser.

**Allow sensitive argument values to be passed in via files.**
Let’s say your command takes a secret via a `--password` argument.
A raw `--password` argument will leak the secret into `ps` output and potentially shell history.
It’s easy to misuse.
Consider allowing secrets only via files, e.g. with a `--password-file` argument.
**Do not read secrets directly from flags.**
When a command accepts a secret, eg. via a `--password` argument,
the argument value will leak the secret into `ps` output and potentially shell history.
And, this sort of flag encourages the use of insecure environment variables for secrets.

Consider accepting sensitive data only via files, e.g. with a `--password-file` argument, or via `STDIN`.
A `--password-file` argument allows a secret to be passed in discreetly, in a wide variety of contexts.

(It’s possible to pass a file’s contents into an argument in Bash by using `--password $(< password.txt)`.
Unfortunately, not every context in which a command is run will have access to magical shell substitutions.
For example, `systemd` service definitions, `exec` system calls, and some `Dockerfile` command forms do not support the substitutions available in most shells.
What’s more, this approach has the same security issue of leaking the file’s contents into places like the output of `ps`.
This approach has the same security issue of leaking the file’s contents into the output of `ps`.
It’s best avoided.)

### Interactivity {#interactivity}
Expand Down Expand Up @@ -1076,21 +1075,22 @@ Here’s a [list of POSIX standard env vars](https://pubs.opengroup.org/onlinepu

**Check general-purpose environment variables for configuration values when possible:**

- `NO_COLOR`, to disable color (see [Output](#output)).
- `DEBUG`, to enable more verbose output.
- `EDITOR`, if you need to prompt the user to edit a file or input more than a single line.
- `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY` and `NO_PROXY`, if you’re going to perform network operations.
- `NO_COLOR`, to disable color (see [Output](#output))
- `DEBUG`, to enable more verbose output
- `EDITOR`, if you need to prompt the user to edit a file or input more than a single line
- `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY` and `NO_PROXY`, if you’re going to perform network operations
(The HTTP library you’re using might already check for these.)
- `SHELL`, if you need to open up an interactive session of the user's preferred shell.
- `SHELL`, if you need to open up an interactive session of the user's preferred shell
(If you need to execute a shell script, use a specific interpreter like `/bin/sh`)
- `TERM`, `TERMINFO` and `TERMCAP`, if you’re going to use terminal-specific escape sequences.
- `TMPDIR`, if you’re going to create temporary files.
- `HOME`, for locating configuration files.
- `PAGER`, if you want to automatically page output.
- `LINES` and `COLUMNS`, for output that’s dependent on screen size (e.g. tables).
- `TERM`, `TERMINFO` and `TERMCAP`, if you’re going to use terminal-specific escape sequences
- `TMPDIR`, if you’re going to create temporary files
- `HOME`, for locating configuration files
- `PAGER`, if you want to automatically page output
- `LINES` and `COLUMNS`, for output that’s dependent on screen size (e.g. tables)

**Read environment variables from `.env` where appropriate.**
If a command defines environment variables that are unlikely to change as long as the user is working in a particular directory, then it should also read them from a local `.env` file so users can configure it differently for different projects without having to specify them every time.
If a command defines environment variables that are unlikely to change as long as the user is working in a particular directory,
then it should also read them from a local `.env` file so users can configure it differently for different projects without having to specify them every time.
Many languages have libraries for reading `.env` files ([Rust](https://crates.io/crates/dotenv), [Node](https://www.npmjs.com/package/dotenv), [Ruby](https://github.com/bkeepers/dotenv)).

**Don’t use `.env` as a substitute for a proper [configuration file](#configuration).**
Expand All @@ -1105,6 +1105,16 @@ Many languages have libraries for reading `.env` files ([Rust](https://crates.io

If it seems like these limitations will hamper usability or security, then a dedicated config file might be more appropriate.

**Do not read secrets from environment variables.**
While environment variables may be convenient for storing secrets, they have proven too prone to leakage:
- Exported environment variables are sent to every process, and from there can easily leak into logs or be exfiltrated
- Shell substitions like `curl -H "Authorization: Bearer $BEARER_TOKEN"` will leak into globally-readable process state.
(cURL offers the `-H @filename` alternative for reading sensitive headers from a file.)
- Docker container environment variables can be viewed by anyone with Docker daemon access via `docker inspect`
- Environment variables in systemd units are globally readable via `systemctl show`

Secrets should only be accepted via credential files, pipes, `AF_UNIX` sockets, secret management services, or another IPC mechanism.

### Naming {#naming}

The name of your program is particularly important on the CLI: your users will be typing it all the time, and it needs to be easy to remember and type.
Expand Down

0 comments on commit ce86821

Please sign in to comment.