Read our newest book, Fundamentals of DevOps and Software Delivery, for free!

How to securely store secrets in 1Password CLI and load them into your ZSH shell when needed

Headshot of Pete Emerson

Pete Emerson

APR 11, 2023 | 4 min read
Zack wrote a post titled “How to securely store secrets in BitWarden CLI and load them into your ZSH shell when needed.” This is a companion piece, with my own twist.In this blog post, I’ll show you how to quickly and easily use the command line to retrieve secrets from 1Password and set environment variables so that your credentials are available when needed but never stored unencrypted on your local computer.

As the demo shows, there are no GitHub environment variables set initially. We then use env-op (a shortened form of “environment — 1Password”) to retrieve the github demo credentials from 1password. It prompts us for our fingerprint or password, and then the credentials are loaded into the environment variables named in the username field of the credential.Since we use a convention of storing the name of the environment variables in the username field in 1password, env-op can load arbitrary environment variables, and the naming of those variables is determined via the credential itself.Let’s walk through the process.

1Password has excellent docs for their CLI. You can find them, along with comprehensive installation instructions, here.

In this case, I’ve named the API Credential “github demo”. Note that the username contains two entries separated by a space: GITHUB_TOKEN and GITHUB_OAUTH_TOKEN. The credential stored will be loaded into both environment variables.

The API Credential should now be stored and available from the op command line. We can verify this:
# Check to see that the credentials we stored are available to the op binary $ op item get 'github demo' --fields username GITHUB_TOKEN GITHUB_AUTH_TOKEN # You might skip this so that your secret is not exposed to STDOUT $ op item get 'github demo' --fields credential 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

Open ~/.zsh_autoload_functions/env-op for editing and write the following to the file:
env-op() { local search="$@" keys_string=$(op item get --fields label=username "$search") if [[ $? != 0 ]] ; then return fi values_string=$(op item get --fields label=credential "$search") read -A keys <<< "$keys_string" read -A values <<< "$values_string" # If we store "AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY" in the username field # and "secret1 secret2" in the password field, we'll map them accordingly. # If there are fewer secrets than usernames (space separated), then we'll # use the last value for the rest of the secrets mapped to usernames. # For example: "GITHUB_TOKEN GITHUB_AUTH_TOKEN" with a password of "foo" will # set both environment variables to "foo". for ((i = 1 ; i <= $#keys ; i++)) ; do if [[ "$values[$i]" != "" ]] ; then last_value=$values[$i] fi export $keys[$i]=$last_value >&2 echo "Loaded $keys[$i]" done } env-op "$@"
Note that you can store multiple environment variables (and values) in the same 1password credential! If there are fewer values than keys, the last value will be mapped to the rest of the keys. This could be useful for storing AWS credentials (the access key ID and the secret access key) in one 1Password entry (although we do recommend using aws-vault for such credentials).

Open your ~/.zshrc file and add the following lines to it:
# Autoload zsh shell functions defined in the function path fpath=( ~/.zsh_autoload_functions "${fpath[@]}" ) autoload -Uz env-op
The first line tells ZSH to look for functions defined in the ~/.zsh_autoload_functions directory.The second line states that ZSH should treat the env-op function as a function and autoload it using the ZSH shell style.Write these changes to your ~/.zshrc file, then save it and run zsh in a new shell to ensure your latest changes are loaded.You can now invoke env-op "name of 1password api credential" and enter your main vault password (or use your fingerprint if that is configured) to have your credentials easily exported for use.

Explore our latest blog

Get the most up-to-date information and trends from our DevOps community.
TerraformResouces Image

Promotion Workflows with Terraform

How to configure GitOps-driven, immutable infrastructure workflows for Terraform using Gruntwork Patcher.

Jason Griffin

October 3, 2023 7 min read
TerraformResouces Image

The Impact of the HashiCorp License Change on Gruntwork Customers

How to configure GitOps-driven, immutable infrastructure workflows for Terraform using Gruntwork Patcher.

Josh Padnick

October 3, 2023 7 min read