#!/bin/bash SEARCH=envwarden usage() { echo "envwarden: use Bitwarden to manage server secrets" echo "" echo "Get your secure environment variables from Bitwarden onto your server." echo "envwarden searches your Bitwarden vault for items matching" echo "a search criteria (defaults to 'envwarden')." echo "Then it goes through all custom fields on every item found" echo "and make them available as envirnoment variables." echo "" echo "Usage: envwarden [--help] [--search] [--dotenv] [--copy]" echo "" echo "To export environment variables, use: \`eval \$(envwarden)\`" echo "To create an .env file, use: \`envwarden --dotenv > .env\`" echo "" echo "Options:" echo -e "\t-h --help" echo -e "\t-s --search (optional) define the search term for bitwarden items (defaults to $SEARCH)" echo -e "\t-d --dotenv (optional) outputs secrets to stdout in .env format" echo -e "\t-k --dotenv-docker (optional) outputs secrets to stdout in a \"docker-friendly\" .env format (no quotes)" echo -e "\t-c --copy (optional) copies attachments matching glob pattern to a folder" echo -e "\t-g --github envs to github actions" echo -e "\t-ss --skip-sync (optional) skip the vault sync (default will sync on every invocation)" echo "" echo "You can use ~/.envwarden to store your credentials (email, email:password, or email:password:client_secret)" echo "See https://bitwarden.com/help/article/cli-auth-challenges/#get-your-personal-api-key" } while [[ $# > 0 ]]; do key="$1" case $key in -h | --help) usage exit ;; -d | --dotenv) DOTENV=true ;; -g | --github) GITHUB_ACTIONS=true ;; -k | --dotenv-docker) DOTENV_DOCKER=true ;; -s | --search) SEARCH=$2 shift ;; -ss | --skip-sync) SKIP_SYNC=true ;; -c | --copy) COPY_GLOB=$2 COPY_TO=$3 COPY_TO=${COPY_TO:=.} shift shift ;; *) echo "ERROR: unknown parameter \"$PARAM\"" usage exit 1 ;; esac shift done if [ -z "$BW_SESSION" ]; then if [[ -f $HOME/.envwarden ]]; then IFS=':' read -r bw_login bw_password bw_client_secret <<< `cat $HOME/.envwarden` else (>&2 echo ".envwarden file not found in $HOME ... prompting for credentials") fi bw logout > /dev/null export BW_SESSION="`BW_CLIENTSECRET=$bw_client_secret bw login $bw_login $bw_password --raw`" fi if [[ -z $SKIP_SYNC ]]; then bw sync > /dev/null if [[ $? != 0 ]]; then (>&2 echo "unable to login or sync with bitwarden.") exit 1 fi fi if [[ -z "$COPY_TO" ]]; then while read -r key; do read -r value if [[ -n "$DOTENV" ]]; then echo $key=\"$value\" elif [[ -n "$DOTENV_DOCKER" ]]; then echo $key=$value elif [[ -n "$GITHUB_ACTIONS" ]]; then echo 'echo "::set-output name='$key'::'$value'"' else # wrap keys and values in single quotes to avoid further interpolation, # plus sanitize for single quote symbols to avoid command injection quoted_key="$(echo "$key" | sed "s/'/'\"'\"'/g")" quoted_value="$(echo "$value" | sed "s/'/'\"'\"'/g")" echo export \'$quoted_key\'=\'$quoted_value\' fi done < <(bw list items --search "$SEARCH" |jq -r '.[].fields[]? | select(.name != null) | select(.value != null) | .name, .value') fi if [[ -n "$COPY_TO" ]]; then item_id=$(bw list items --search "$SEARCH" |jq -r '.[].id') if [[ -n "$item_id" ]]; then tmp_folder=`mktemp -d` while read -r attachment_id; do read -r filename # we want to glob match the $COPY_GLOB, e.g. to be able to specify envwarden -c encrpt*.txt /tmp # and it would download encrypted.txt to /tmp # to make glob matching work, we touch the filename inside a tmp folder and then # test it against the glob. If it matches, we actually get the file, otherwise we skip. touch "$tmp_folder/$filename" if test -n "$(find $tmp_folder -maxdepth 1 -name "$COPY_GLOB" -print -quit)"; then bw get attachment $attachment_id --itemid $item_id --output "$COPY_TO/$filename" 1>&2 else (>&2 echo "skipping $filename") fi done < <(bw list items --search "$SEARCH" |jq -r '.[].attachments[] | .id, .fileName') fi fi