# Vaultwarden и использование секретов Краткое руководство по **Vaultwarden** в homelab и по тому, как получать секреты из него в скриптах и при восстановлении. --- ## Что такое Vaultwarden **Vaultwarden** — это self-hosted реализация API Bitwarden: менеджер паролей, совместимый с официальными клиентами Bitwarden (десктоп, мобильные приложения, браузерные расширения). Данные хранятся на вашем сервере, а не в облаке Bitwarden. В нашей схеме Vaultwarden развёрнут на **контейнере 103** (Gitea). Доступ: - **Веб:** https://vault.katykhin.ru (из LAN и по VPN; из интернета без VPN закрыт). - **По IP в LAN:** http://192.168.1.103:8280. Подробнее про установку, порты и NPM — в [Контейнер 103 (Gitea, Vaultwarden)](containers/container-103.md#5-vaultwarden-менеджер-паролей). **Зачем хранить секреты в Vaultwarden:** - Один источник правды для паролей хоста, БД, API-ключей и т.д. - При восстановлении после сбоя не нужно искать креды по разным файлам. - Скрипты бэкапов и уведомлений могут брать секреты через Bitwarden CLI без хранения паролей в репозитории. --- ## Доступ к секретам: веб и CLI - **Веб-интерфейс** — для ручного просмотра и редактирования записей (логины, пароли, кастомные поля). Вход по email и мастер-паролю. - **Bitwarden CLI (`bw`)** — для скриптов и командной строки: разблокировка хранилища, получение логина/пароля/полей по имени записи. Далее в статье речь идёт в основном о **CLI**. --- ## Установка и настройка Bitwarden CLI (bw) На машине, с которой нужно получать секреты (например, хост Proxmox), должны быть установлены **`bw`** и **`jq`**. ### Установка bw (Linux, вручную) 1. Скачать архив с [релизов Bitwarden CLI](https://github.com/bitwarden/cli/releases) (например `bw-linux-1.22.1.zip` для x86_64). 2. Распаковать и положить бинарник в PATH, например: ```bash unzip bw-linux-*.zip install -m 755 bw /usr/local/bin/bw ``` 3. Установить `jq` (для разбора кастомных полей): ```bash apt install jq # Debian/Proxmox ``` ### Настройка сервера и первый вход 1. Указать URL вашего Vaultwarden: ```bash bw config server https://vault.katykhin.ru ``` 2. Войти (интерактивно, один раз): ```bash bw login ``` Ввести email и мастер-пароль от vault.katykhin.ru. Данные сессии сохранятся локально. 3. Проверить: ```bash bw status bw sync ``` После ввода мастер-пароля (если хранилище было locked) синхронизация подтянет актуальные данные с сервера. ### Разблокировка для скриптов (файл с мастер-паролем) В cron или в скриптах пароль вводить вручную нельзя. Используют **файл с мастер-паролем** с строгими правами: ```bash echo -n 'ВАШ_МАСТЕР_ПАРОЛЬ' > /root/.bw-master chmod 600 /root/.bw-master ``` - Файл **не коммитить** в репозиторий и не копировать в открытые места. - Владелец — пользователь, под которым запускаются скрипты (например `root`); только он должен иметь доступ к файлу. Проверка разблокировки без интерактивного ввода: ```bash bw unlock "$(cat /root/.bw-master)" --raw ``` Команда должна вернуть длинную строку (session key). Эту строку скрипты передают в `BW_SESSION` (см. ниже). --- ## Как получать секреты из Vaultwarden ### Состояние и синхронизация - **`bw status`** — показать URL сервера, последнюю синхронизацию, email пользователя и состояние: `unlocked` / `locked`. - **`bw sync`** — обновить локальный кэш с сервера (при необходимости перед чтением актуальных данных). Если хранилище **locked**, перед любыми `bw get ...` нужно разблокировать: ```bash export BW_SESSION=$(bw unlock --passwordfile /root/.bw-master --raw) ``` Дальше в этой же сессии (пока переменная `BW_SESSION` экспортирована) можно вызывать `bw get ...`. ### Логин и пароль записи Для записей типа «логин» (Login) в Vaultwarden: - **Логин (username):** `bw get username "ИМЯ_ЗАПИСИ"` - **Пароль:** `bw get password "ИМЯ_ЗАПИСИ"` Примеры: `bw get password "GITEA"`, `bw get username "PAPERLESS"`. Имя записи — то, как она называется в веб-интерфейсе (чувствительно к регистру). ### Кастомные поля (custom fields) В Bitwarden/Vaultwarden у записи могут быть **кастомные поля** (например `RESTIC_REPOSITORY`, `TELEGRAM_SELF_CHAT_ID`). Они не выводятся через `bw get username/password`, их достают через **`bw get item`** и **`jq`**: ```bash bw get item "ИМЯ_ЗАПИСИ" | jq -r '.fields[] | select(.name=="ИМЯ_ПОЛЯ") | .value' ``` Примеры: - Поле `RESTIC_BACKUP_KEY` из записи **RESTIC:** `bw get item "RESTIC" | jq -r '.fields[] | select(.name=="RESTIC_BACKUP_KEY") | .value'` - Поле `TELEGRAM_SELF_CHAT_ID` из **RESTIC:** `bw get item "RESTIC" | jq -r '.fields[] | select(.name=="TELEGRAM_SELF_CHAT_ID") | .value'` Полный JSON записи (все поля): `bw get item "ИМЯ_ЗАПИСИ" | jq '.'` --- ## Использование в скриптах ### Общий подход 1. В начале скрипта (если ещё не разблокировано) прочитать мастер-пароль из файла и разблокировать: ```bash BW_MASTER_PASSWORD_FILE="${BW_MASTER_PASSWORD_FILE:-/root/.bw-master}" if [ -f "$BW_MASTER_PASSWORD_FILE" ]; then export BW_SESSION=$(bw unlock --passwordfile "$BW_MASTER_PASSWORD_FILE" --raw) fi ``` 2. При необходимости выполнить `bw sync`. 3. Получить нужные значения через `bw get username`, `bw get password`, `bw get item ... | jq ...` и присвоить переменным окружения или использовать в командах. Переменная **`BW_SESSION`** передаётся в дочерние процессы, поэтому все вызовы `bw` в том же процессе и в дочерних скриптах будут видеть разблокированное хранилище. ### Пример: Restic (репозиторий и ключ из Vaultwarden) ```bash # Разблокировать (мастер-пароль из файла с chmod 600) BW_MASTER_PASSWORD_FILE="${BW_MASTER_PASSWORD_FILE:-/root/.bw-master}" if [ -f "$BW_MASTER_PASSWORD_FILE" ]; then export BW_SESSION=$(bw unlock --passwordfile "$BW_MASTER_PASSWORD_FILE" --raw) fi ITEM=$(bw get item "RESTIC") export RESTIC_REPOSITORY=$(echo "$ITEM" | jq -r '.fields[] | select(.name=="RESTIC_REPOSITORY") | .value') export AWS_ACCESS_KEY_ID=$(echo "$ITEM" | jq -r '.fields[] | select(.name=="AWS_ACCESS_KEY_ID") | .value') export AWS_SECRET_ACCESS_KEY=$(echo "$ITEM" | jq -r '.fields[] | select(.name=="AWS_SECRET_ACCESS_KEY") | .value') export AWS_DEFAULT_REGION=$(echo "$ITEM" | jq -r '.fields[] | select(.name=="AWS_DEFAULT_REGION") | .value') RESTIC_PASSWORD=$(echo "$ITEM" | jq -r '.fields[] | select(.name=="RESTIC_BACKUP_KEY") | .value') export RESTIC_PASSWORD_FILE=$(mktemp -u) echo -n "$RESTIC_PASSWORD" > "$RESTIC_PASSWORD_FILE" chmod 600 "$RESTIC_PASSWORD_FILE" trap 'rm -f "$RESTIC_PASSWORD_FILE"' EXIT # Дальше: restic backup ... и т.д. ``` Пароль restic в файле — временный; `trap` удаляет его по выходу из скрипта. ### Пример: Telegram (токен и chat_id из Vaultwarden) Токен бота хранится в записи **HOME_BOT_TOKEN** (пароль = токен); chat_id — в записи **RESTIC**, поле `TELEGRAM_SELF_CHAT_ID`: ```bash BW_MASTER_PASSWORD_FILE="${BW_MASTER_PASSWORD_FILE:-/root/.bw-master}" if [ -f "$BW_MASTER_PASSWORD_FILE" ]; then export BW_SESSION=$(bw unlock --passwordfile "$BW_MASTER_PASSWORD_FILE" --raw) fi TELEGRAM_BOT_TOKEN=$(bw get password "HOME_BOT_TOKEN") TELEGRAM_CHAT_ID=$(bw get item "RESTIC" | jq -r '.fields[] | select(.name=="TELEGRAM_SELF_CHAT_ID") | .value') # Дальше: curl к Telegram API с TELEGRAM_BOT_TOKEN и TELEGRAM_CHAT_ID ``` ### Fallback на старые конфиги Если Vaultwarden недоступен или разблокировка не удалась, скрипты могут загружать креды из прежних файлов (например `/root/.telegram-notify.env`, `/root/.restic-yandex.env`). Так можно обеспечить работу бэкапов даже при временной недоступности vault. --- ## Безопасность - **Файл с мастер-паролем:** только владелец (например root), права `chmod 600`. Не хранить в git и не копировать на общие ресурсы. - **Переменная BW_SESSION:** не логировать и не выводить в скриптах; не передавать в ненадёжные процессы. - **Временные файлы с паролями** (как RESTIC_PASSWORD_FILE выше): создавать с `chmod 600`, удалять по завершении (`trap ... EXIT`). - **Бэкап данных Vaultwarden:** каталог `/opt/docker/vaultwarden/data` на CT 103 входит в план бэкапов (restic → Yandex), см. [backup-howto](backup/backup-howto.md). Без этого при потере сервера теряется и хранилище паролей. --- ## Инвентаризация записей и полей В Vaultwarden удобно хранить записи с именами, совпадающими с сервисами: **RESTIC**, **GITEA**, **PAPERLESS**, **NEXTCLOUD**, **HOME_BOT_TOKEN**, **VAULTWARDEN**, **MIRAN_S3** и т.д. У записей типа «логин» — логин/пароль; у записей с множеством значений — кастомные поля (например `RESTIC_REPOSITORY`, `AWS_ACCESS_KEY_ID`). Полная таблица «где лежат креды сейчас → какой объект в Vaultwarden» и готовые команды `bw get ...` / `jq` по каждому объекту описаны в [Фаза 1: Стратегия бэкапов](backup/proxmox-phase1-backup.md) — разделы «Инвентаризация секретов для переноса в Vaultwarden», «Получение секретов из Vaultwarden» и «Переключение скриптов на секреты из Vaultwarden». --- ## См. также - [Контейнер 103 (Gitea, Vaultwarden)](containers/container-103.md) — развёртывание Vaultwarden, порты, домен, NPM. - [Фаза 1: Стратегия бэкапов](backup/proxmox-phase1-backup.md) — инвентаризация секретов, команды по объектам, переключение скриптов на Vaultwarden. - [backup-howto](backup/backup-howto.md) — общий план бэкапов и восстановления, в том числе данных Vaultwarden.