Бекап паролей Vaultwarden

Всем привет

Посоветуйте как можно автоматизировать бекап паролей на сервере Vaultwarden? В идеале я бы хотел при выполнении бекапа конвертировать CSV/JSON в Keepass формат. Вроде как это возможно. Но для любого экспорта паролей из Vaultwarden используя CLI нужно вводить мастер пароль. То есть его нужно хранить в условно открытом виде. Считаю что env не решает проблему (ну либо я не знаю как). Даже с учётом того, что это происходит локально на домашнем сервере - я бы не хотел его хранить в открытом виде. У меня достаточно сложный пароль, я знаю его наизусть и я храню его только в самой базе паролей.

В общем с, возможно ли сделать бекап паролей сервера Vaultwarden не вводя мастер пароль в какой-то стандартизированный формат? Например Json или CSV. Пусть они и будут секунду в открытом виде. Я автоматизирую шифрование этого файла открытым GPG ключем

Хочу уйти с Keepass для удобства синхронизации и доступа. Но пока не могу из-за лёгкой паранойи по бекапам

пароли находятся в зашифрованном хранилище и для расшифровки надо некоторое время (особенно при импорте)

отсюда следует, что нельзя просто так взять и сконвертировать шифрованые пароли в другой вид хранения, а значит нужно вводить ключ

делай бекап данных или всей машины и все

у нас так делается на 2 разных pbs

Вообще, странная паранойя на тему бэкапирования и отсутствие ее по безопасности.
Присоединяюсь к предыдущему оратору по всем пунктам.
У меня

  1. создается бэкап всего LXC контейнера
  2. Запускается скрипт бэкапирования данных
docker compose exec vaultwarden /vaultwarden backup
find vw-data/ -name 'db_*.sqlite3' -mtime +1 -delete
docker compose run --rm proxmox-backup-client /do_backup.sh

Не красиво, но работает

Нашел еще вот такой репозиторий, но все сводится к бэкапированию зашифрованных данных

Ну и можно почитать официальную доку по бэкапированию

Привет! Возможно, это не совсем то, что вам нужно, но, может быть, кому-то пригодится. Скрипт для архивации и копирования папки data на второй диск с примонтированной директорией /mnt/backups_bw. Скрипт запускается по cron каждый день в 4 утра.

После успешного или неудачного копирования я получаю уведомление в своем Telegram-боте.

#!/bin/bash
# ===== Строгий режим =====
set -euo pipefail

# ===== PATH для cron =====
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

# ===== Telegram =====
TG_BOT_TOKEN="${TELEGRAM_BOT_TOKEN:-}"
TG_CHAT_ID="${TELEGRAM_CHAT_ID:-}"
TG_API_URL="https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMessage"

# ===== Переменные =====
source_dir="/vw-data"                 # Что бэкапим
backup_dir="/mnt/backups_bw"          # Куда сохраняем
log_file="/var/log/vw_backup.log"     # Лог-файл
max_archives=15                       # Максимум архивов

# ===== Создание каталогов =====
mkdir -p "$backup_dir"
mkdir -p "$(dirname "$log_file")"

# ===== Логирование =====
exec >> "$log_file" 2>&1

# ===== Функция отправки сообщений в Telegram =====
send_telegram() {
  local message="$1"
  curl -s -X POST "$TG_API_URL" \
  --data-urlencode "chat_id=$TG_CHAT_ID" \
  --data-urlencode "text=$message" \
  --data-urlencode "parse_mode=HTML" >/dev/null || true
}

# ===== Обработчик ошибок =====
on_error() {
  local exit_code=$?
  send_telegram "❌ <b>Бэкап НЕ выполнен</b>
🖥 Хост: <b>$(hostname)</b>
⚠️ Код ошибки: <b>$exit_code</b>
🕐 Время: $(date '+%d-%m-%Y %H:%M:%S')"
}
# Ловим ошибки
trap on_error ERR

# ===== Старт (пишется в лог-файл) =====
echo "===== $(date '+%d-%m-%Y %H:%M:%S') Запуск бэкапа ====="
start_time=$(date +%s)

# ===== Проверка существования исходной директории =====
if [ ! -d "$source_dir" ]; then
  echo "ОШИБКА: Исходная директория $source_dir не найдена"
  exit 1
fi

# ===== Временная директория =====
temp_dir=$(mktemp -d)
trap 'rm -rf "$temp_dir"' EXIT

# ===== Имя архива =====
backup_file="vw-data_$(date +"%d-%m-%Y").tar.gz"

# ===== Проверка свободного места =====
source_size_kb=$(du -sk "$source_dir" | awk '{print $1}')
free_space_kb=$(df -k "$backup_dir" | awk 'NR==2 {print $4}')
required_space_kb=$(( source_size_kb * 12 / 10 ))

if (( free_space_kb < required_space_kb )); then
  echo "ОШИБКА: недостаточно свободного места. Нужно: ${required_space_kb}KB, Есть: ${free_space_kb}KB"
  exit 1
fi

# ===== Копирование данных =====
rsync -a "$source_dir"/ "$temp_dir"/

# ===== Архивация =====
tar -czf "$backup_dir/$backup_file" -C "$temp_dir" .

# ===== Ротация архивов =====
ls -1t "$backup_dir"/*.tar.gz 2>/dev/null | tail -n +"$((max_archives + 1))" | xargs -r rm -f

# ===== Успешное завершение =====

# Вычисляем время выполнения
end_time=$(date +%s)
duration=$(( end_time - start_time ))
if (( duration > 60 )); then
  duration_str="$((duration / 60)) мин $((duration % 60)) сек"
else
  duration_str="$duration сек"
fi

# Получаем размер готового архива
archive_size=$(du -h "$backup_dir/$backup_file" | awk '{print $1}')

# Получаем свободное место на диске бэкапов
free_space=$(df -h "$backup_dir" | awk 'NR==2 {print $4}')

# Отправляем сообщение
send_telegram "✅ <b>Бэкап успешно выполнен</b>
🖥 Хост: <b>$(hostname)</b>
📦 Архив: <code>$backup_file</code>
⚖️ Размер: <b>$archive_size</b>
⏱ Затрачено: <b>$duration_str</b>
💾 Свободно на диске: <b>$free_space</b>
🕐 Время: $(date '+%d.%m.%Y %H:%M:%S')"

echo "Бэкап успешно завершён. Размер: $archive_size, Затрачено: $duration_str"
echo

Чтобы не отправлять сообщение «Бэкап выполнен успешно», просто закомментируйте или удалите код.