1Password plugin
DMNOâs 1Password plugin allows you to securely access your stored secrets in 1Password. This plugin uses the 1Password CLI by means of a Service Account. It is compatible with any account type. Note that rate limits vary by account type, you can read more about that in the 1Password Developer documentation.
Installation
Install the package in your service(s) that will use config from 1password.
npm add @dmno/1password-plugin
pnpm add @dmno/1password-plugin
yarn add @dmno/1password-plugin
After installation, youâll need to initialize the plugin in your dmno config and wire it up to the config path that will hold your 1password service account token. Itâs ok if you have not created this service account yet - weâll do that in the next section.
import { OnePasswordDmnoPlugin, OnePasswordTypes } from '@dmno/1password-plugin';
const OnePassBackend = new OnePasswordDmnoPlugin('1pass/prod', { token: configPath('OP_TOKEN'),});
export default defineDmnoService({ schema: { OP_TOKEN: { extends: OnePasswordTypes.serviceAccountToken, // NOTE - the type itself is already marked as sensitive đ }, },});
Injecting the plugin in monorepo services
In a monorepo, if you are managing config for multiple services in a single vault, you should initialize the plugin instance once in your root service as seen above, and then inject it in the child services. Note we need that same id we set during initialization.
import { OnePasswordDmnoPlugin } from '@dmno/1password-plugin';
// inject the already initialized plugin instead of re-initializing itconst OnePassBackend = OnePasswordDmnoPlugin.injectInstance('1pass/prod');
Setup vault & service account
-
Create a vault in your 1Password account. This is where youâll store your secrets. You can create multiple vaults for different environments or services. link
-
Create a service account in your 1Password account. This is a separate account that has access to the vault(s) you created. You can create multiple service accounts for different environments or services. link
-
Grant vault access to the service account. This is done in the 1Password web interface. You can add multiple service accounts to a single vault. link
This service account token will now serve as your âsecret-zeroâ - which grants access to the rest of your sensitive config stored in 1password. It must be set locally and in deployed environments, and as it is sensitive, we must pass in the value as an override rather than storing it within the config. Locally this usually means storing it in your .env.local
and on a deployed environment youâll usually set it within some kind of UI, wherever you would normally pass in secrets.
OP_TOKEN=ops_abc123...
Note that the config path of OP_TOKEN
is arbitrary and you can see how it was wired up from the config to the plugin input above. If you are using multiple vaults and service accounts, you may have something more like OP_PROD_TOKEN
and OP_NON_PROD_TOKEN
.
Add your items
DMNO supports a few different ways to reference items in 1Password.
Using a env blob (recommended)
Managing lots of individual 1password items and connecting them to your config can be a bit tedious, so we recommend storing multiple items together in a .env
style text blob. Using this method, weâll have a single 1password item that can have one text entry per service containing the .env
blob. This would be similar to applying a .env.local
file as overrides, except they are secured and shared via 1password. This also makes it incredibly easy to migrate from using local .env
files.
To use this method, we need to tell the plugin which 1password item will store our .env
blob(s). As this value is static and not sensitive, we can use a static value as our plugin input.
import { OnePasswordDmnoPlugin, OnePasswordTypes } from '@dmno/1password-plugin';
const OnePassBackend = new OnePasswordDmnoPlugin('1pass/prod', { token: configPath('OP_TOKEN'), envItemLink: 'https://start.1password.com/open/i?a=I3GUA2KU6BD3FBHA47QNBIVEV4&v=ut2dftalm3ugmxc6klavms6tfq&i=n4wmgfq77mydg5lebtroa3ykvm&h=dmnoinc.1password.com',});
export default defineDmnoService({ schema: { OP_TOKEN: { extends: OnePasswordTypes.serviceAccountToken, }, SOME_SECRET_ITEM: { sensitive: true, value: OnePassBackend.item(), } },});
Using specific 1password items
If you already have lots of indivdual items in 1password, or you just donât want to use the blob method, you can wire up invididual config items to specific 1password items. We provide several methods to do so. Note that while a 1password reference (e.g., op://vaultname/itemname/path
) points all the way to a specific value, the other methods only get us to an item which usually contains multiple entries (account id, secret key, etc). In these cases you must also pass in an additional path to the specific entry. These paths use the entry labels.
export default defineDmnoService({ schema: { // using item private link ITEM_WITH_LINK: { value: OnePassBackend.itemByLink( 'https://start.1password.com/open/i?a=I3GUA2KU6BD3FBHA47QNBIVEV4&v=ut2dftalm3ugmxc6klavms6tfq&i=n4wmgfq77mydg5lebtroa3ykvm&h=dmnoinc.1password.com', 'somepath', ), }, // using vault + item UUIDs ITEM_WITH_IDS: { value: OnePassBackend.itemById('vaultUuid', 'itemUuid', 'somepath'), }, // using item reference ITEM_WITH_REFERENCE: { value: OnePassBackend.itemByReference('op://vaultname/itemname/path'), }, },});