Инструменты пользователя

Инструменты сайта


raspberry_pi:pi_4_model_b:raspberry_pi_os:vaultwarden

Установка Vaultwarden на Raspberry Pi OS с nginx

Уже лет как пять я периодически подумывал об обновлении стратегии хранения личных, корпоративных и паролей клиентов, а так же их передачи. До сегодняшнего дня, много-много лет, я использовал классический PasswordSafe на компьютерах и, с 2017, pwSafe на iPhone с синхронизацией криптоконтейнеров через iCloud. Но доступность этого решения оставляет желать… желать и желать, увы!

Сейчас же, существует огромное количество решений, доступность которых находится совершенно на другом уровне! Но с увеличением доступности, падает надежность – особенно меня всегда смущало расположение базы данных неизвестно где и у кого! Еще более в этом месте волнует полнейшее отсутствие гарантий, что завтра этот сервис будет все так же онлайн… причем по самому огромному спектру причин, зачастую даже не зависящих от воли владельцев сервиса!

Но сравнительно недавно у меня посвился Raspberry Pi 4 Model B и тут возможности заиграли новыми красками!

Требования

  1. Freeware, Open Source и Self-hosted;
  2. наличие клиентов iPhone, Windows и Web;
  3. возможность корпоративного использования.

Муки выбора

Мук, как таковых, на самом деле и не было – пробежался по интерфейсам Open Source систем, имеющих self-hosted решения, выбрал, что больше нравится и соответствует моим требованиям, погуглил немного отзывы и историю, в итоге остановился на Bitwarden'e. Далее осталось выбрать реализацию сервиса.

Vaultwarden

Но и тут особых сложностей не возникло – по сути, Vaultwarden ничем не отличается от официального сервера1), кроме того, что он более «легкий» и имеет на борту разблокированные платные, а тут бесплатные, функции. Выбор очевиден2)! 8-)

Возможности

В итоге я получил:

  1. легкий онлайн менеджер паролей, физически расположенный на полностью подконтрольном мне сервере,
  2. с клиентами под все платформы3), включая плагины для популярных браузеров,
  3. и возможностью создания организаций с предоставлением настраиваемого доступа к ним.

Система

Все манипуляции проводятся на 64-битной Raspberry Pi OS 11 (bullseye):

  • Vaultwarden 1.28.1;
  • Docker 23.0.5;
  • nginx 1.18.0;
  • snap 2.58.2;
  • certbot 2.5.0.

Для удобства авторизовываемся под суперпользователем

sudo -s

Docker

  1. добавляем сертификат репозитория4)

    curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/docker.gpg
  2. добавляем репозиторий

    echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/trusted.gpg.d/docker.gpg] https://download.docker.com/linux/debian "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
  3. обновляем списки пакетов и систему

    apt update && apt upgrade
  4. устанавливаем зависимости

    apt install ca-certificates curl gnupg
  5. устанавливаем пакеты Docker

    apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Ошибка

В моем случае, во время конфигурирования пакета «docker-ce» появилась ошибка запуска службы «invoke-rc.d: initscript docker, action "start" failed. (code=exited, status=1/FAILURE)», а journalctl -xe ни сказал вообще ничего интересного кроме «Failed to start Docker Application Container Engine».

А вот при попытке запуска демона dockerd напрямую уже появилось что-то интересное:

ERRO[2023-04-28T20:59:30.882570089+10:00] failed to mount overlay: no such device       storage-driver=overlay2
ERRO[2023-04-28T20:59:30.882760347+10:00] exec: "fuse-overlayfs": executable file not found in $PATH  storage-driver=fuse-overlayfs
WARN[2023-04-28T20:59:30.896634105+10:00] Running modprobe bridge br_netfilter failed with message: modprobe: WARNING: Module bridge not found in directory /lib/modules/6.1.19-v8+
modprobe: WARNING: Module br_netfilter not found in directory /lib/modules/6.1.19-v8+, error: exit status 1

Немного погуглив, выполнил rpi-update5) и reboot, что однозначно помогло, но не совсем – служба начала запускаться, но при попытке загрузить контейнер стала появляться ошибка «Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?»… при том, что docker daemon is running!

Решил попробовать откатиться к стабильным версиям

sudo apt install --reinstall libraspberrypi0 libraspberrypi-{bin,dev,doc} raspberrypi-bootloader raspberrypi-kernel

что помогло уже окончательно!

После всех манипуляций, для окончательной установки пакета, нужно выполнить

sudo apt install docker-ce

Vaultwarden

  1. Загружаем контейнер

    docker pull vaultwarden/server:latest
  2. придумываем или генерируем ключ аутентификации для админ-панели

    openssl rand -base64 48
  3. генерируем хэш ключа Argon2id6)

    docker run --rm -it vaultwarden/server /vaultwarden hash
  4. и запускаем контейнер с указанием всех необходимых параметров

    docker run -d -e ADMIN_TOKEN='$argon2id$v=XX$m=XXXXX,t=X,p=X$HASH' -e TZ='Asia/Vladivostok' -e WEBSOCKET_ENABLED=true --restart unless-stopped --name vaultwarden -v /opt/vaultwarden/:/data/ -p 127.0.0.1:8080:80 -p 127.0.0.1:3012:3012 vaultwarden/server:latest
    • «-e ADMIN_TOKEN» – переменная окружения с ключом аутентификации для административного раздела7);
    • «-e TZ» – указание часового пояса сервера в формате «Регион/Город», к примеру, «Asia/Vladivostok»;
    • «-e WEBSOCKET_ENABLED» – включение уведомлений web-сокета8);
    • «--restart unless-stopped» – автозапуск контейнера при перезагрузке и прочих ситуациях9);
    • «-v /opt/vaultwarden/:/data/» – назначение расположения каталога с данными вне контейнера10);
    • «-p 127.0.0.1:8080:80» и «-p 127.0.0.1:3012:3012» – привязка интерфейса и порта web-сервера и web-сокета11).

Внешний доступ

Для дальнейшей настройки, необходим «белый» IP-адрес и общедоступный домен. Для примера, ниже будут использоваться следующие условности:

  • внешний домен – «vw.example.zone»;
  • белый IP-адрес – AAA.AAA.AAA.AAA;
  • внешний порт web-сервера – 768412);
  • IP-адрес сервера – XXX.XXX.XXX.XXX.

Ну и, соответственно, доступ к маршрутизатору, обладающему этим IP.

nginx

Т.к. nginx у меня уже установлен и обслуживает систему мониторинга LibreNMS, мне нужно исправить конфигурацию последней, для возможности использования ее в получении сертификата Let's Encrypt, и добавить отдельную конфигурацию для Vaultwarden.

LibreNMS висит на 80-м порту и должен быть доступен только внутри сети, поэтому:

  1. открываем конфигурацию

    nano /etc/nginx/sites-enabled/librenms.vhost
  2. и в начале, после директивы «listen», вставляем общее ограничение на доступ

    allow XXX.XXX.XXX.0/24;
    deny all;
  3. а в конце, перед закрывающим тегом «}» секции «server», добавляем настройку

    location /.well-known/acme-challenge {
           allow all;
           alias /tmp/vaultwarden/ssl/;
    }
  4. создаем соответствующую папку

    mkdir -p /tmp/vaultwarden/ssl/
  5. открываем временную конфигурацию Vaultwarden

    nano /etc/nginx/sites-enabled/vaultwarden.vhost
  6. и добавляем в нее13)

    server {
           listen 8081;
           server_name vw.example.zone;
    }
  7. перечитываем конфигурацию nginx

    systemctl reload nginx

MikroTik

Конфигурация маршрутизатора сводится к публикации портов 80/768414) и, если необходимо, настройке NAT Loopback.

vaultwarden.rsc
# Server Publishing
/ip firewall nat
add action=netmap chain=dstnat comment="Publishing .well-known and Vaultwarden" dst-address=AAA.AAA.AAA.AAA dst-port=80,7684 protocol=tcp to-addresses=XXX.XXX.XXX.XXX
/ip firewall filter
add action=accept chain=forward comment="Accept .well-known and Vaultwarden" dst-address=XXX.XXX.XXX.XXX dst-port=80,7684 in-interface=Internet-1 protocol=tcp
 
# NAT Loopback
/ip firewall mangle
add action=mark-packet chain=prerouting comment="Mark Vaultwarden packets from LAN" connection-state=new dst-address=AAA.AAA.AAA.AAA in-interface-list=LAN new-packet-mark=nat-loopback passthrough=yes
/ip firewall nat
add action=masquerade chain=srcnat comment="Masquerade Vaultwarden from LAN" packet-mark=nat-loopback

Сертификат

snap

  1. Устанавливаем15) демона snap и перезагружаемся

    apt install snapd && reboot
  2. авторизовываемся под суперпользователем

    sudo -s
  3. устанавливаем основные компоненты

    snap install core
    • если они уже стояли, то обновляем

      snap refresh core

certbot

  1. Проверяем16), чтобы certbot не был установлен с помощью apt

    apt remove certbot
  2. устанавливаем из репозитория snap

    snap install --classic certbot && ln -s /snap/bin/certbot /usr/bin/certbot
  3. получаем сертификат

    certbot -d vw.example.zone --nginx

    Что странно, больше ничего не потребовалось… сертификаты без лишних вопросов сохранил сюда «/etc/letsencrypt/live/vw.example.zone/»… и добавил в конфиг «/etc/nginx/sites-enabled/vaultwarden.vhost» нужные строки.

  4. проверяем перевыпуск сертификата в симуляции

    certbot renew --dry-run

Конфигурация

Осталось добавить полноценную конфигурацию обратного прокси:

  1. открываем

    nano /etc/nginx/sites-enabled/vaultwarden.vhost
  2. копируем директивы «ssl_certificate», «ssl_certificate_key», «include» и «ssl_dhparam», добавленные certbot
  3. добавляем и исправляем рекомендованную конфигурацию17)

    vaultwarden.vhost
    # The `upstream` directives ensure that you have a http/1.1 connection
    # This enables the keepalive option and better performance
    #
    # Define the server IP and ports here.
    upstream vaultwarden-default {
      zone vaultwarden-default 64k;
      server 127.0.0.1:8080;
      keepalive 2;
    }
    upstream vaultwarden-ws {
      zone vaultwarden-ws 64k;
      server 127.0.0.1:3012;
      keepalive 2;
    }
     
    # Redirect HTTP to HTTPS #1
    #server {
    #    listen 80;
    #    listen [::]:80;
    #    server_name vaultwarden.example.tld;
    #    return 301 https://$host$request_uri;
    #}
     
    server {
        listen 7684 ssl http2;
    #   listen [::]:443 ssl http2; #2
        server_name vw.example.zone;
     
        # Specify SSL Config when needed #3
        ssl_certificate /etc/letsencrypt/live/vw.example.zone/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/vw.example.zone/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
     
        client_max_body_size 128M;
     
        location / {
          proxy_http_version 1.1;
          proxy_set_header "Connection" "";
     
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
     
          proxy_pass http://vaultwarden-default;
        }
     
        location /notifications/hub/negotiate {
          proxy_http_version 1.1;
          proxy_set_header "Connection" "";
     
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
     
          proxy_pass http://vaultwarden-default;
        }
     
        location /notifications/hub {
          proxy_http_version 1.1;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";
     
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header Forwarded $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
     
          proxy_pass http://vaultwarden-ws;
        }
     
        # Optionally add extra authentication besides the ADMIN_TOKEN
        # Remove the comments below `#` and create the htpasswd_file to have it active
        #
        #location /admin {
        #  # See: https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-http-basic-authentication/
        #  auth_basic "Private";
        #  auth_basic_user_file /path/to/htpasswd_file;
        #
        #  proxy_http_version 1.1;
        #  proxy_set_header "Connection" "";
        #
        #  proxy_set_header Host $host;
        #  proxy_set_header X-Real-IP $remote_addr;
        #  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        #  proxy_set_header X-Forwarded-Proto $scheme;
        #
        #  proxy_pass http://vaultwarden-default;
        #}
    }

    Пояснения к изменениям в конфигурации по умолчанию:

    • отключаем (#1) публикацию по протоколу HTTP и, соответственно, перенаправление на HTTPS;
    • отключаем (#2) привязку IPv6;
    • добавляем (#3) пути к сертификатам, скопированные ранее.

  4. перечитываем конфигурацию

    systemctl reload nginx
  5. профит!

Настройка

Админ-панель доступна по адресу «https://vw.example.zone:7684/admin».

Из важного, в ней необходимо установить параметр «General settings» → «Domain URL»18), который должен соответствовать установленным выше параметрам. В данном контексте должно быть так – «https://vw.example.zone:7684».

Остальные параметры сугубо на свое усмотрение.

Разве что, после всех настроек, желательно отключить регистрацию в «General settings» → «Allow new signups» и полностью отключить админ-панель:

  1. удаляем контейнер19)

    docker stop vaultwarden && docker rm vaultwarden
  2. открываем конфигурацию

    nano /opt/vaultwarden/config.json

    и удаляем из нее строку «admin_token»

  3. регистрируем контейнер заново без переменной окружения «-e ADMIN_TOKEN»

    docker run -d -e TZ='Asia/Vladivostok' -e WEBSOCKET_ENABLED=true --restart unless-stopped --name vaultwarden -v /opt/vaultwarden/:/data/ -p 127.0.0.1:8080:80 -p 127.0.0.1:3012:3012 vaultwarden/server:latest

Обновление

Обновление, в моем случае, с версии 1.28.1 до 1.30.1 простейшее и описано ниже, но!

:!: В этой версии служба web-сокета на отдельном порту оставлена только в режиме совместимости, т.е. она не будет обновляться, и в ближайшем будущем будет вообще удалена! Поэтому обновление на более свежую версию, вероятно, уже потребует изменения конфигурации обратного прокси.

  1. Авторизуемся под суперпользователем

    sudo -s
  2. загружаем новый образ

    docker pull vaultwarden/server:latest
  3. останавливаем и удаляем старый контейнер

    docker stop vaultwarden & docker rm vaultwarden
  4. настраиваем и запускаем новый

    docker run -d -e TZ='Asia/Vladivostok' -e WEBSOCKET_ENABLED=true --restart unless-stopped --name vaultwarden -v /opt/vaultwarden/:/data/ -p 127.0.0.1:8080:80 -p 127.0.0.1:3012:3012 vaultwarden/server:latest

На этом, собственно, все.

  • Очистить Docker от накопившегося хлама, выполнив команду

    docker system prune -a

    но надо быть осторожным, т.к. не удаляет она только запущенные контейнеры и соответствующие им образы!

  • Узнать текущую версию сервера можно, выполнив команду

    sudo docker logs vaultwarden | grep "Version" -m 1

Резервное копирование

Для резервного копирования можно использовать этот скрипт с такой конфигурацией20):

files.txt
/etc/nginx/sites-enabled/vaultwarden.vhost
/opt/vaultwarden/
sqlitedbs.txt
/opt/vaultwarden/db.sqlite3

Дисклеймер

  • Использование материалов данной базы знаний разрешено на условиях лицензии, указанной внизу каждой страницы! При использовании материалов активная гиперссылка на соответствующую страницу данной базы знаний обязательна!
  • Автор не несет и не может нести какую либо ответственность за последствия использования материалов, размещенных в данной базе знаний. Все материалы предоставляются по принципу «как есть». Используйте их исключительно на свой страх и риск.
  • Все высказывания, мысли или идеи автора, размещенные в материалах данной базе знаний, являются исключительно его личным субъективным мнением и могут не совпадать с мнением читателей!
  • При размещении ссылок в данной базе знаний на интернет-страницы третьих лиц автор не несет ответственности за их техническую функциональность (особенно отсутствие вирусов) и содержание! При обнаружении таких ссылок, можно и желательно сообщить о них в комментариях к соответствующей статье.
1)
Вот короткий список того, что не реализовано и, вероятно, никогда не будет реализовано.
2)
Да, тут могут быть проблемы с аудитом кода, но… понадеемся на паникеров от сообщества с открытым исходным кодом, которые вовремя поднимут тревогу!
3)
Причем некоторые работают в режиме кэшировая, т.е. при отсутствии доступа к серверу, доступ к данным остается.
5)
Читайте официальное предупреждение касательно использования этой команды!
6)
Подробнее в официальной документации.
7)
Может быть указан в прямом виде или в виде хэша, сгенерированного выше.
8)
Подробнее, если надо.
10)
До двоеточия, это путь в системе, а после – в контейнере.
11)
В целях безопасности лучше использовать только локальный интерфейс, но, в принципе, ip-адрес можно вообще не указывать, ограничившись сопоставлением портов.
12)
Чем он менее интуитивен, тем лучше.
13)
Порт не важен, главное, чтобы он был свободен.
14)
3012 публиковать не надо!
16)
Официальная инструкция.
19)
Это безопасно! Данные останутся на месте!

Обсуждение

Ваш комментарий:
Z V W​ M E R U O D H O T W O B N
 
Последнее изменение: 2023/12/20 23:06 — Николай Солошин