labnotes

Using 1password from a script

better than keeping keys around

tags
1password
cli

First, install if you haven't:

1
  brew install 1password-cli

Check if it works:

1
  which op

Then open your 1password app, go to Settings > Developer and Integrate with 1Password CLI.

List the vaults

See which vaults you have access to:

1
  op vaults list
ID                            NAME
26qksmfapwaq2s.....           Personal

It should ask you to open the vault each time.

Getting the full document

And example would be

1
  op item get 'Resend API'
ID:          go6jxv7zgslinwotun2uj4q4qe
Title:       Resend API
Vault:       Personal (26qksmfapwaq2siqwsfcxrh6d4)
Created:     10 minutes ago
Updated:     10 minutes ago by Will Schenk
Favorite:    false
Version:     1
Category:    SECURE_NOTE
Fields:
  notesPlain:    re_XYEvJ5TV_8a....

And if you want to get the raw value pipe it through JQ:

1
  op item get 'Resend API' --format json | jq -r '.fields[0].value'
re_XYEvJ5TV_8a...

Reading it directly

1
  op read 'op://Personal/Resend API/notesPlain'
re_XYEvJ5TV_8a...

Using it in a script

There are a couple of ways to do this but here is how you'd do it from the secret scripts section of the docs.

First we create an environment file like env:

1
2
  # environment
  RESEND_API=op://Personal/Resend API/notesPlain

Then we can make a simple node script that sends a message using the API:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
  // send.js
  import { Resend } from 'resend';

  if( process.env.RESEND_API === undefined ) {
      console.log( "Please set RESEND_API" );
      process.exit(1);

  }

  const resend = new Resend(process.env.RESEND_API);

  resend.emails.send({
    from: 'onboarding@resend.dev',
    to: 'wschenk@gmail.com',
    subject: 'Hello World',
    html: '<p>Congrats on sending your <strong>first email</strong>!</p>'
  });

  console.log( "email sent!" );

With the package.json:

1
2
3
4
5
6
  {
      "type": "module",
      "dependencies": {
          "resend": "^3.5.0"
      }
  }

Then we can try it out without 1password:

1
  node send.js
Please set RESEND_API

And then with 1password:

1
  op run --env-file environment -- node send.js
email sent!

Injecting into a config file

Maybe you don't want it to prompt you everytime, and you want to cache the results. For that you inject, which takes the template and outputs a file that can, hopefully, be secretly shared around

1
  op inject -i environment -o .env
/Users/wschenk/willschenk.com/content/labnotes/2024/using_1password_from_a_script/.env

Then you can use the normal dotenv way of loading in things. It really depends on how and when you are running the scripts, and if its only triggered by you doing it or if it runs somewhere else.

Server install

What happens if you don't want to ship the cleartext files around? Install 1password on the server!

Here's the debian instructions.

Add the key for the 1Password apt repository:

1
2
  curl -sS https://downloads.1password.com/linux/keys/1password.asc | \
  sudo gpg --dearmor --output /usr/share/keyrings/1password-archive-keyring.gpg

Add the 1Password apt repository:

1
2
  echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/1password-archive-keyring.gpg] https://downloads.1password.com/linux/debian/$(dpkg --print-architecture) stable main" |
  sudo tee /etc/apt/sources.list.d/1password.list

Add the debsig-verify policy:

1
2
3
4
5
6
sudo mkdir -p /etc/debsig/policies/AC2D62742012EA22/
curl -sS https://downloads.1password.com/linux/debian/debsig/1password.pol | \
sudo tee /etc/debsig/policies/AC2D62742012EA22/1password.pol
sudo mkdir -p /usr/share/debsig/keyrings/AC2D62742012EA22
curl -sS https://downloads.1password.com/linux/keys/1password.asc | \
sudo gpg --dearmor --output /usr/share/debsig/keyrings/AC2D62742012EA22/debsig.gpg

Install 1Password CLI:

1
  sudo apt update && sudo apt install 1password-cli

Service Accounts

Service accounts don't work with personal vaults, so back on your home machine lets create a new one:

1
  op vault create Production
ID:                   ursbnjfomqcdmz2fym3l3kgjhe
Name:                 Production
Type:                 USER_CREATED
Attribute version:    1
Content version:      1
Items:                0
Created:              now
Updated:              now

Copy the item over:

1
2
  op item get 'Resend API' --format json  | \
      op item create --vault Production
ID:uxoawzbzw2bprash6fhlo3q3yq
Title:ResendAPI
Vault:Production(ursbnjfomqcdmz2fym3l3kgjhe)
Created:now
Updated:now
Favorite:false
Version:1
Category:SECURE_NOTE
Fields:
notesPlain:re_XYEvJ5TV_8a….

Now we can create a service account

1
2
  op service-account create "server" \
     --expires-in 30d --vault Production:read_items
Service account created successfully!
Service account UUID: AME6P4DMKFHMFC5HPQGMQZUVAQ
Service account token: 
ops_eyJzaWduSW5BZGRyZXNzIjoiaHR0cHM6...

To start using this service account, run the following command:

export OP_SERVICE_ACCOUNT_TOKEN=ops_eyJzaWduSW5BZGRyZXNzIjoiaHR0cHM6...

Keep this somewhere because it'll go away

Back to the server

1
2
3
  export OP_SERVICE_ACCOUNT=ops_eyJ....

  op read 'op://Production/Resend API/notesPlain'

And then you have access to the secrets!

Previously

fragments

Thoughts on reading the llama 3.1 paper

tags
ai

Next

labnotes

Sending email with react-email

its nicer to use their interative builder but why not just the simple thing

tags
react
email
htmlq
reactemail