Automatically update your secrets and environment variables from a 1Password vault

Last updated February 11, 2022 by Jacob Paris

Set up .env file

Create a .env file with a variable DEVELOPMENT_ENVS_UPDATED and set it to the current date.

# Update this whenever you make changes to the file
DEVELOPMENT_ENVS_UPDATED=2022-JAN-11

Set up 1Password vault

Follow the instructions on this guide to importing secrets from 1Password to set up a 1Password vault.

When you are done, you will have 4 pieces of information to assign to environment variables.

PASSWORD_TOKEN PASSWORD_CREDENTIALS VAULT_ID ENV_FILE_ID

Create a file sync-env.sh

#!/bin/bash -u
apology () {
echo "💬 Could not update .env file due to missing $1. Check 1Password for the latest .env file"
}
: ${VAULT_ID:?"$(apology VAULT_ID)"}
: ${ENV_FILE_ID:?"$(apology ENV_FILE_ID)"}
: ${PASSWORD_TOKEN:?"$(apology PASSWORD_TOKEN)"}
: ${PASSWORD_CREDENTIALS:?"$(apology PASSWORD_CREDENTIALS)"}
if [ ! "$(command -v docker)" ]; then
echo "💬 Could not update .env file automatically. Check 1Password for the latest variables"
echo "🐳 Docker daemon not installed. Install docker to fetch .env file automatically"
exit 1
fi
docker stop op-connect-api 2>/dev/null && docker rm op-connect-api
docker stop op-connect-sync 2>/dev/null && docker rm op-connect-sync
echo $PASSWORD_CREDENTIALS > "1password-credentials.json"
docker run -d \
--name op-connect-api \
-p 8080:8080 \
-v "$(pwd)/1password-credentials.json:/home/opuser/.op/1password-credentials.json" \
-v "data:/home/opuser/.op/data" \
1password/connect-api:latest
docker run -d \
--name op-connect-sync \
-p 8081:8080 \
-v "$(pwd)/1password-credentials.json:/home/opuser/.op/1password-credentials.json" \
-v "data:/home/opuser/.op/data" \
1password/connect-sync:latest
gp await-port 8080
sleep 5
curl -L "http://0.0.0.0:8080/v1/vaults/$VAULT_ID/items/$ENV_FILE_ID" \
-H "Authorization: Bearer $PASSWORD_TOKEN" \
| jq -r .fields[0].value \
> .env
echo "Stopping container…"
docker stop op-connect-api && docker rm op-connect-api
echo "Stopping container…"
docker stop op-connect-sync && docker rm op-connect-sync
rm "1password-credentials.json"
echo "Updated .env file"

Create a file sync-env.js

const fs = require('fs')
const path = require('path')
/**
* Load environment variables from .env
*
* If they are out of date, or do not exist, download and update them
* If they are newer than this file, update this file
*/
module.exports = function syncEnvFile() {
require('dotenv').config()
/** This variable will update itself when the .env does */
const LATEST_ENVS_DATE = '2022-JAN-11'
if (
process.env.DEVELOPMENT_ENVS_UPDATED !==
LATEST_ENVS_DATE
) {
if (!process.env.DEVELOPMENT_ENVS_UPDATED) {
console.error('The .env file is missing')
} else {
const claimedDate = new Date(
process.env.DEVELOPMENT_ENVS_UPDATED,
)
const latestDate = new Date(
LATEST_ENVS_DATE,
)
if (claimedDate > latestDate) {
const thisFilename =
path.basename(__filename)
console.info(
`Updating ${thisFilename} to`,
process.env.DEVELOPMENT_ENVS_UPDATED,
)
console.log('Please commit this change')
const thisFile = fs.readFileSync(
thisFilename,
'utf8',
)
const occurrences =
thisFile.split(LATEST_ENVS_DATE)
.length - 1
if (occurrences !== 1)
throw new Error(
'Cannot automatically update',
)
fs.writeFileSync(
thisFilename,
thisFile.replace(
LATEST_ENVS_DATE,
process.env.DEVELOPMENT_ENVS_UPDATED,
),
'utf-8',
)
return
} else {
console.error(
'The .env file changed on',
LATEST_ENVS_DATE,
)
}
}
const {execSync} = require('child_process')
console.log(
'Downloading latest .env file from 1Password…',
)
try {
execSync('sh sync-env.sh', {
encoding: 'utf-8',
})
console.log(
'The .env file is now up to date',
)
} catch (error) {
console.error(error.stdout.toString())
}
process.exit(1)
} else {
console.log('The .env file is up to date')
}
}

Usage

As early as possible in your application, add this line of code. In a node server, this is probably the top of your index.js, main.js, or server.js

if (process.env.NODE_ENV !== 'production') {
// Update and load .env file
require('./sync-env')()
}

Error cases

Missing 1Password environment variables

The .env file is missing Downloading latest .env file from 1Password… sync-env.sh: line 7: VAULT_ID: 💬 Could not update .env file due to missing VAULT_ID. Check 1Password for the latest .env file ```