Bitwarden Secrets Sync for Docker Stacks (Prefix Logic)

1. The Strategy: One Project, Multiple Stacks

This setup uses a Prefix-Based Routing system. It allows you to use a single Bitwarden project for all your home lab secrets while keeping them isolated per Docker stack on your Raspberry Pi.

  • Logic: The script looks at the folder name in /opt/stacks/ (e.g., papra), converts it to uppercase (PAPRA), and fetches all Bitwarden secrets starting with PAPRA_.

  • Transformation: It strips the PAPRA_ prefix so your app just sees the standard variable (e.g., AUTH_SECRET).

 


 

2. The Master Sync Script: sync-secrets.sh

This script uses your existing .bashrc token. I have added a Dry-Run mode: if you run the script with -d, it will show you what it found without touching your files.

File: ~/sync-secrets.sh

Bash

#!/bin/bash


 

# --- CONFIGURATION ---

STACKS_ROOT="/opt/stacks"

USER_ID=1000

GROUP_ID=1000

DRY_RUN=false


 

# Check for Dry-Run flag

if [[ "$1" == "-d" || "$1" == "--dry-run" ]]; then

    DRY_RUN=true

    echo "--- DRY RUN MODE: No files will be modified ---"

fi


 

# 1. Fetch secrets (Uses BWS_ACCESS_TOKEN from your environment)

if [ -z "$BWS_ACCESS_TOKEN" ]; then

    echo "Error: BWS_ACCESS_TOKEN not found. Run 'source ~/.bashrc' or check your config."

    exit 1

fi


 

SECRETS_JSON=$(bws secret list)


 

# 2. Iterate through every stack folder

for dir in "$STACKS_ROOT"/*/; do

    FOLDER_NAME=$(basename "$dir")

    PREFIX=$(echo "$FOLDER_NAME" | tr '[:lower:]' '[:upper:]')

    TARGET_FILE="${dir}stack.env"


 

    # 3. Filter and Strip Prefix

    MATCHING_SECRETS=$(echo "$SECRETS_JSON" | jq -r --arg P "${PREFIX}_" '.[] | select(.key | startswith($P)) | "\(.key | sub($P; ""))=\(.value)"')


 

    if [ -n "$MATCHING_SECRETS" ]; then

        if [ "$DRY_RUN" = true ]; then

            echo "Would update $FOLDER_NAME with:"

            echo "$MATCHING_SECRETS" | sed 's/=.*/=********/' # Hide values in dry run

        else

            echo "Updating $TARGET_FILE..."

            echo "$MATCHING_SECRETS" > "$TARGET_FILE"

            chown $USER_ID:$GROUP_ID "$TARGET_FILE"

            chmod 644 "$TARGET_FILE"

        fi

    else

        echo "No secrets found for $FOLDER_NAME (looked for ${PREFIX}_)"

    fi

done


 


 

3. Usage & Testing

To Test (Dry-Run):

This will list which folders would be updated and which keys were found (with masked values):

Bash

bash ~/sync-secrets.sh -d


 

To Run for Real:

Bash

bash ~/sync-secrets.sh


 

 


 

4. Setting up the Automated Cron Job

Since your token is in .bashrc, we need to tell Cron where to find it (as Cron doesn't load your personal bash profile by default).

  1. Open crontab: crontab -e

  2. Add this line (runs every 30 mins):

Bash

*/30 * * * * . /home/pi/.bashrc; /bin/bash /home/pi/sync-secrets.sh >> /home/pi/sync.log 2>&1


 

Note: The . /home/pi/.bashrc; part tells Cron to load your variables (including the token) before running the script.

 


 

Summary of Dockge Setup

To ensure Dockge uses these secrets correctly:

  1. Name your secret in Bitwarden: STAKNAME_VARIABLE (e.g., PAPRA_AUTH_SECRET).

  2. In your docker-compose.yaml, add the env_file: pointing to stack.env.

  3. Reference the variable as ${VARIABLE} (e.g., ${AUTH_SECRET}).