At some point in time, we all have to set secrets in our terminal. If you want to keep your dotfiles in git this becomes a problem. There are plenty of creative ways around that issue but I’ve found sourcing passwords directly from a secret manager a great way to keep your secrets up to date, your dotfiles clean and no sensitive passwords lying around on disk. In this post I will show you how I source my passwords directly from 1password.

I’m assuming before diving in that you already have a 1password account.

Setting Up 1password CLI

First, let’s install the 1password CLI

brew install --cask 1password-cli

Once you have the CLI installed, you need to know your 1password signin address. This is the url you use to signin to reach your vaults. So maybe yours is something like doodoo.1password.com/signin. Well your signin key for the op CLI is then doodoo and you would then login like this

op signin doodoo

Once you know that information you can place this in your ~/.zshrc or ~/.bashrc and load this on every new terminal session

eval "$(op signin doodoo)"

Every time you launch a terminal it will now ask for your 1password password and you will have access to your secrets

Enter the password for <your-email@email.com> at doodoo.1password.com:

Loading Secrets

So now that you are logged in, how do you source secrets into your shell? Here is an example from one of my secrets (the content has been changed). I’ve removed a lot of unnecessary data from this payload just to show the structure.

 op get item github-pat --vault Private | jq .
{
  ...
  "details": {
    "fields": [],
    "notesPlain": "",
    "password": "some-random-long-password-string",
    "passwordHistory": [],
    "sections": []
  },
  "overview": {
    "title": "github-pat",
  }
}

This is really useful, but even more useful is the op CLI provides a --fields flag to return just the data you need. So we can return a single piece of information using this flag like so.

❯ op get item github-pat --fields password --vault Private
some-random-long-password-string

Awesome, right? So now, retrieving and setting this in your environment becomes as simple as placing this in some of your dotfiles

export GITHUB_TOKEN=$(op get item github-pat --fields password --vault Work)

Automatically Logging In With iTerm (Optional)

Typing in your password to login is pretty annoying. There is a way to automate this in iTerm using Triggers. Whenever a certain phrase appears, iTerm will dropdown a select to use passwords from its Vault. If you navigate to iTerm -> Preferences -> Profiles -> Advanced there will be a section that says Triggers, click Edit.

1password iTerm trigger

When you create a new trigger you want the regular expression to trigger on to be doodoo.1password.com and the action you want is Open Password Manager. For parameters I have 1password set with instant and enabled checked.

Now that you have that setup you need place the password in your password manager. To do this, navigate to Windows -> Password Manager and create an entry for 1password. This is what the Trigger will look for when it finds a match for doodoo.1password.com.

Now if you create a new iTerm session you should immediately see a dropdown whenever Enter the password for <your-email@email.com> at doodoo.1password.com: appears!

Going Further With direnv

The icing on the cake for me is I use all of this in conjunction with direnv. This little project loads environment variables by walking directories and looking for .envrc files to load. In conjunction with 1password this means you can load environment variables from your secret manager depending on your directly location. Here is an example of my directory structure for programming:

 /Users/redman/code
 ├── work
+|   ├── .envrc
 │   └── twilio
 ├── github.com
+|   ├── .envrc
 │   ├── rossedman
 │   │   └── rossedman.github.io

Each of these directories requires different github secrets. The way direnv works is it will load the .envrc for all directories under the .envrc. Each of these directories now loads the appropriate access token when I’m working in them so I don’t have to switch or think about changing it. It loads it directly from 1password so its always up to date. If I need to rotate a PAT, I replace it in 1password and open a new terminal.

Here are what each .envrc looks like. Notice that I name the secrets the same and place them in different Vaults as well. This gives me clean separation in 1password.

# work .envrc
export GITHUB_TOKEN=$(op get item github-pat --fields password --vault Work)

# personal .envrc
export GITHUB_TOKEN=$(op get item github-pat --fields password --vault Personal)

Now when you navigate to these directories it will load from 1password. Here is an example

❯ cd ~/code/work
direnv: loading ~/code/work/.envrc
direnv: export ~GITHUB_TOKEN ~GITHUB_URL

Conclusion

That’s it! I hope you learned something. I believe this is a very effective way to manage passwords especially for multipurpose computers where you need to switch contexts frequently and also need a secure solution to not store passwords on disk. Of note, that if you store your password in iTerm's Password Manager you are removing some of the security benefits of this. If someone ever accessed your laptop they would also be able to just hit Return and get passwords. Happy hacking!