During episode 183 of Python Bytes, I mentioned that I keep all unencrypted secrets off of my filesystem and use tools like 1Password's CLI tool, op, to put them into my environment when needed. Here are some examples of how that works.
I initially wanted to just quickly grab my VPN password so I could paste it into the dialog box without leaving the terminal.
Before you get to any of these examples, you'll need to be logged into the 1Password CLI and then you'll be able to make a session with 1Password like this:
% eval $(op signin sixfeetup)
Doing this creates a OP_SESSION_sixfeetup="mysessionstring"
variable in your environment that will timeout after 30 minutes of inactivity.
Now you can use the op
command to grab items and the awesome jq tool to fish out the bits you want and to make your JSON output pretty.
In this example, I get the item by its identifier, but you can also grab items based on their name as I show later. I pipe that output to jq
to extract the password
field and then copy it to my clipboard.
First, let's find the entry we want. Running this will get it all of the items in our vault.
% op list items --vault demo | jq
Which looks like this:
[
{
"uuid": "odhmws2n64ihs7yjxbtejq4pxe",
"templateUuid": "001",
"trashed": "N",
"createdAt": "2020-06-04T12:43:22Z",
"updatedAt": "2020-06-04T12:43:47Z",
"changerUuid": "R7ANQT74JVHLDJCAIBRNBDHEKA",
"itemVersion": 1,
"vaultUuid": "rrkhdlddmwzxk422smzuqt4bza",
"overview": {
"URLs": [
{
"l": "website",
"u": "https://vpn.example.com"
}
],
"ainfo": "calvin@sixfeetup.com",
"pbe": 127.500789,
"pgrng": true,
"ps": 100,
"tags": [],
"title": "Demo VPN",
"url": "https://vpn.example.com"
}
}
]
To explore further, let's get the specific item:
% op get item odhmws2n64ihs7yjxbtejq4pxe | jq
:::json
{
"uuid": "odhmws2n64ihs7yjxbtejq4pxe",
"templateUuid": "001",
"trashed": "N",
"createdAt": "2020-06-04T12:43:22Z",
"updatedAt": "2020-06-04T12:43:47Z",
"changerUuid": "R7ANQT74JVHLDJCAIBRNBDHEKA",
"itemVersion": 1,
"vaultUuid": "rrkhdlddmwzxk422smzuqt4bza",
"details": {
"fields": [
{
"designation": "username",
"name": "username",
"type": "T",
"value": "calvin@sixfeetup.com"
},
{
"designation": "password",
"name": "password",
"type": "P",
"value": "9{ji+1xvE?sp0huB5zjH"
}
],
"notesPlain": "",
"passwordHistory": [],
"sections": []
},
"overview": {
"URLs": [
{
"l": "website",
"u": "https://vpn.example.com"
}
],
"ainfo": "calvin@sixfeetup.com",
"pbe": 127.500789,
"pgrng": true,
"ps": 100,
"tags": [],
"title": "Demo VPN",
"url": "https://vpn.example.com"
}
}
Now, let's write a shell function that can grab the password using a jq
query and put it into the clipboard for us to use.
grabVpnPass() {
op get item odhmws2n64ihs7yjxbtejq4pxe | jq -j '.details.fields[]|select(.name=="password")|.value' | xclip -selection clipboard
}
What is important here is the -j
flag used with jq
. This tells jq
to give us the raw output and to not put a newline with it. Otherwise we would have extra junk on our clipboard when we go to paste it.
One improvement I'd make to this would be to have it removed from the clipboard after some time, but haven't gotten around to it yet.
It's common when using certain tools that they support getting secrets out of your environment instead of passing them on the command line. This is also convenient if you don't want to type or paste the password over and over if you are being prompted for the secret.
Here is an example entry:
% op get item "Demo API Keys" | jq
Which provides this output with a new sections
key for us to use.
{
"uuid": "dveqj446lixw2lel57thissg7u",
"templateUuid": "001",
"trashed": "N",
"createdAt": "2020-06-04T13:02:24Z",
"updatedAt": "2020-06-04T14:17:20Z",
"changerUuid": "R7ANQT74JVHLDJCAIBRNBDHEKA",
"itemVersion": 2,
"vaultUuid": "rrkhdlddmwzxk422smzuqt4bza",
"details": {
"fields": [
{
"designation": "username",
"name": "username",
"type": "T",
"value": "calvin@sixfeetup.com"
},
{
"designation": "password",
"name": "password",
"type": "P",
"value": "Rhj=Mznbfck6<$waqx]R"
}
],
"notesPlain": "",
"passwordHistory": [],
"sections": [
{
"fields": [
{
"k": "string",
"n": "p7w3hi5tpnmidg25fy2wpnoppm",
"t": "API_SECRET",
"v": "8b017d4a-180f-4c8c-8e34-3dfe8d923279"
},
{
"k": "string",
"n": "m4rtdcl22wfaa4zngsok35asnu",
"t": "API_KEY",
"v": "7806ce50-afe6-4a4f-a21b-ed916f28f869"
}
],
"name": "Section_qacx7ow27jaoo7llqbv6evjpri",
"title": "Keys"
}
]
},
"overview": {
"URLs": [],
"ainfo": "calvin@sixfeetup.com",
"pbe": 127.500789,
"pgrng": true,
"ps": 100,
"tags": [],
"title": "Demo API Keys",
"url": ""
}
}
It has a Section called Keys and we can grab the variable name and value and export them into our environment.
Here is an example shell function that can do just that:
demoapienv() {
$(op get item "Demo API Keys" | jq -r '.details.sections[]|select(.title=="Keys").fields[]|.t+"="+.v' | sed -z 's/^/export /; s/\n/ /g')
}
We are using the -r
flag to jq
to ensure we get the raw output and not a JSON version of the result. Otherwise you might get extra quotes around the output. It will grab all key value pairs from that section and export them for you.
That function won't output anything to your terminal, but if you check your environment, you will see you have the variables there that came from 1Password.
% env | grep API
API_SECRET=8b017d4a-180f-4c8c-8e34-3dfe8d923279
API_KEY=7806ce50-afe6-4a4f-a21b-ed916f28f869
Last, here is an example I use daily since we manage AWS environments from many customers that give us credentials into their AWS console. In this function, it takes the first argument and passes it to find the item in 1Password and then specifically only exports keys that start with AWS_
into my environment.
awsenv() {
$(op get item $1 | jq -r '.details.sections[].fields|.[]|select(.t|startswith("AWS_"))|.t+"="+.v' | sed -z 's/^/export /; s/\n/ /g')
}
Also, if you are using LastPass, there is an unofficial CLI wrapper to do this called lpass-env that I used to use before we switched to 1Password. And, if you are a KeePassXC user, it has the keepassxc-cli bundled and you can use to grab your secrets from the command line.
I would love to hear any feedback on this so I can improve how I manage secrets on my local workstation.