Vaultwarden: Set "vault timeout" policy globally

In this guide, I want to show you a small bash script that I have written to set the vault timeout setting globally for all your created organisations in Vaultwarden.

For context: Some settings in vaultwarden can be set and enforced to all connected clients (also called Enterprise Policies). These settings can be set in context of organisations.

Why so complicated?

Because some Enterprise Policies are not AGPLv3 Licensed by Bitwarden and so Vaultwarden can not implement these features.

Prerequisites

  1. You need a running Vaultwarden server. Setup instructions can be found here: https://github.com/dani-garcia/vaultwarden?tab=readme-ov-file#installation
  2. You need to have setup at least one organisation on your Vaultwarden server. More infos about an organisation can be found here: https://bitwarden.com/help/getting-started-organizations/

Script

  1. Open a ssh session to your linux machine were the Vaultwarden container is running.
  2. Temporary stop your Vaultwarden container (because my script is adding/altering/deleting some table entries in the internal sqlite database of your Vaultwarden server.
  3. Make a backup of the Vaultwarden database. If you are using docker to run Vaultwarden, the database sould be here (... replace with your application name): /var/lib/docker/volumes/.../vw-data/db.sqlite3
  4. Create a sh script:

    nano modify_vault_timeout.sh

    Paste the following content into the nano editor and save (Strg+O and Strg+X)

#!/bin/bash

# Check if sqlite3 is installed
if ! command -v sqlite3 &> /dev/null; then
   echo "Error: sqlite3 is not installed."
   echo "Please install sqlite3 before running this script."
   echo "On Debian-based systems, you can install it with:"
   echo "  sudo apt-get install sqlite3"
   echo "On Red Hat-based systems, you can install it with:"
   echo "  sudo yum install sqlite"
   exit 1
fi

# Function to remove all vault timeout entries
remove_atype_9_entries() {
   local remove_query="DELETE FROM org_policies WHERE atype='9';"
   sqlite3 "$DB_FILE" "$remove_query"
   echo "Disabled Enterprise Policy by deleting the DB entry"
}

# Get the SQLite database file path from the user with error handling
while true; do
   clear
   read -p $'Enter the path to the SQLite database file \n(Hint: /var/lib/docker/volumes/.../vw-data/db.sqlite3): ' DB_FILE
   if [ -f "$DB_FILE" ]; then
       break
   else
       clear
       echo "Error: The file does not exist. Please enter a valid file path."
   fi
done

# Get the vault timeout from the user with error handling
while true; do
   clear
   read -p "Enter the vault timeout [in minutes] you want to set for all organizations: " LOCK_TIMEOUT
   if [[ "$LOCK_TIMEOUT" =~ ^[0-9]+$ ]]; then
       break
   else
       clear
       echo "Error: Invalid input. Please enter a valid integer value."
   fi
done

# Get the vault timeout action from user
while true; do
   clear
   read -p "Select the vault timeout action that is performed after the timeout [0=null(UserDefined) or 1=logOut or 2=lock or 3=(disable enterprise policy by deleting the DB entry) ]: " LOCK_ACTION
   if [[ "$LOCK_ACTION" =~ ^[0-3]+$ ]]; then
       if [[ "$LOCK_ACTION" == 0 ]]; then
           LOCK_ACTION="null"
       elif [[ "$LOCK_ACTION" == 1 ]]; then
           LOCK_ACTION="logOut"
       elif [[ "$LOCK_ACTION" == 2 ]]; then
           LOCK_ACTION="lock"
       elif [[ "$LOCK_ACTION" == 3 ]]; then
           REMOVE_OPTION="yes"
       fi
       break
   else
       clear
       echo "Error: Invalid input. Please enter a valid lockout action [0=null(UserDefined) or 1=logOut or 2=lock or 3=(disable enterprise policy by deleting the DB entry)]."
   fi
done

# Perform removal if requested
if [ "$REMOVE_OPTION" == "yes" ]; then
   remove_atype_9_entries
   exit 0
fi

# SQL query to retrieve UUIDs from the organizations table
UUID_QUERY="SELECT uuid FROM organizations;"

# Execute the UUID query and store the result in an array
UUID_ARRAY=()
while IFS= read -r uuid; do
   UUID_ARRAY+=("$uuid")
done < <(sqlite3 "$DB_FILE" "$UUID_QUERY")

# Loop through the UUID array and execute the SQL insert or update query for each UUID
for uuid in "${UUID_ARRAY[@]}"; do
   # Check if org_uuid and atype combination already exists
   if [[ $(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM org_policies WHERE org_uuid='$uuid' AND atype='9';") -gt 0 ]]; then
       # Update existing row with new lock timeout
       UPDATE_QUERY="UPDATE org_policies SET data='{\"minutes\":$LOCK_TIMEOUT,\"action\":\"$LOCK_ACTION\"}' WHERE org_uuid='$uuid' AND atype='9';"
       sqlite3 "$DB_FILE" "$UPDATE_QUERY"
       echo "Vault timeout entry already exists for UUID: $uuid. Updated vault timeout to $LOCK_TIMEOUT minutes and lockout action to $LOCK_ACTION ."
   else
       # Create a random UUID for newly inserted org_policy
       RAND_UUID=$(cat /proc/sys/kernel/random/uuid)
       # Insert new row with lock timeout
       INSERT_QUERY="INSERT INTO org_policies (uuid, org_uuid, atype, enabled, data) VALUES ('$RAND_UUID', '$uuid', '9', '1', '{\"minutes\":$LOCK_TIMEOUT}');"
       sqlite3 "$DB_FILE" "$INSERT_QUERY"
       echo "Inserted new vault timeout entry for UUID: $uuid with a timeout of $LOCK_TIMEOUT minutes and lockout action to $LOCK_ACTION ."
   fi
done
  1. Make the script executable:

    chmod +x modify_vault_timeout.sh
  2. Run the script:

    ./modify_vault_timeout.sh
  3. Start the Vaultwarden container.

Next Post

Add a comment


Comments

I updated the script so that the deleting process of the DB entry is less confusing

Written on Fri, 11 Apr 2025 19:13:24 by SuitDeer
And i found something else.
You have a "exit 0" after you execute the deletion of the entries.
So the insert or update will no be executed if every entry is deleted before.

Written on Tue, 08 Apr 2025 08:47:31 by wastez
You missed the Lock action in the "else" state.
I don't need it but maybe somebody else.

Written on Mon, 07 Apr 2025 13:20:18 by wastez
Perfect, it is working as it should, thanks you for your fast answer.

Written on Mon, 07 Apr 2025 13:14:11 by wastez
Hi wastez,

I have modified my script so that the lockout actions can be defined

Written on Sun, 06 Apr 2025 18:15:54 by SuitDeer
Hello,

Thank you that is working as it should.
Do you know the format how to add it to the db to also force the logout action? I wan't to set it to logout. As i saw it should be the same database type (9). Would be great if you could help me.

Thanks and Greetz

Written on Sat, 05 Apr 2025 20:34:56 by wastez