Vaultwarden

Comment compiler et installer proprement le clone de Bitwarden en Rust. Les bases de données disponibles à ce jour sont MySQL et SQLite (et PostgreSQL, mais ça n’a pas l’air d’être super testé/conseillé).

NB: Vaultwarden s’appelait précédemment Bitwarden_rs et a été renommé le 27 avril 2021. Cette page a été remaniée en conséquence. N’hésitez pas à me signaler des soucis (voir l’adresse mail sur ma page de présentation).

Compilation

Installation des dépendances :

sudo apt install pkg-config libssl-dev build-essential
sudo apt install npm

Si vous voulez utiliser MySQL comme base de données :

sudo apt install default-libmysqlclient-dev

Si vous voulez utiliser PostgreSQL comme base de données :

sudo apt install libpq-dev

Installation de Rust

Installation de rustup, qui nous fournira le compilateur Rust :

curl https://sh.rustup.rs -sSf > rustup.sh

On n’exécute pas direct un script tiré du web ! On regarde d’abord s’il ne va pas faire de saloperies :

vi rustup.sh

On le rend exécutable :

chmod +x rustup.sh

On installe le compilateur Rust (il sera dans notre $HOME) :

./rustup.sh --default-host x86_64-unknown-linux-gnu --default-toolchain nightly

Attention ! Ceci n’est valable que pour l’architecture x86_64 ! Si vous voulez installer Vaultwarden sur une architecture ARM (comme les Raspberry Pi), il faut adapter la commande, a priori en remplaçant `x86_64-unknown-linux-gnu` par `armv7-unknown-linux-gnueabihf`.

On source un fichier qui nous permet de l’appeler

source $HOME/.cargo/env

Mise à jour de Rust (si vous l’avez déjà installé via rustup)

rustup update

Compilations

NB : si vous ne voulez pas vous embêter à compiler l’interface web (ou si ça ne fonctionne pas pour une raison ou pour une autre), vous pouvez utiliser une version pré-compilée par l’auteur de Vaultwarden, à télécharger sur https://github.com/dani-garcia/bw_web_builds/releases.

Gagnons du temps en clonant le projet vaultwarden et l’interface web (qu’il faut compiler aussi) en même temps .

git clone https://github.com/dani-garcia/vaultwarden
git clone https://github.com/bitwarden/web.git web-vault

Compilation de Vaultwarden :

cd vaultwarden
git checkout -b "v$(git tag --sort=v:refname | tail -n1)" "$(git tag --sort=v:refname | tail -n1)"
cargo build --release --features sqlite # ou mysql, ou postgresql, selon la bdd que vous souhaitez utiliser

Le résultat de la compilation est dans vaultwarden/target/release/.

Compilation de l’interface web :

cd ../web-vault
# On se positionne sur le dernier tag en date
git checkout -b "$(git tag --sort=v:refname | tail -n1)" "$(git tag --sort=v:refname | tail -n1)"
npm run sub:init
# Un petit patch pour que ça fonctionne avec notre installation
# Attention, regardez https://github.com/dani-garcia/bw_web_builds/tree/master/patches
# et ce que donne `git tag --sort=v:refname | tail -n1` pour choisir la version de patch la plus proche de votre version de web-vault
wget https://raw.githubusercontent.com/dani-garcia/bw_web_builds/master/patches/v2.12.0.patch
# On vérifie le patch
cat v2.12.0.patch
git apply v2.12.0.patch
npm install
npm run dist

ATTENTION : on m’a dit que la compilation de l’interface web prenait 1,5Gio de RAM, assurez-vous que vous en avez assez de libre.

Si vous faites une mise à jour, supprimez l’ancienne version de l’interface web :

rm -rf ../vaultwarden/target/release/web-vault/

Et on copie l’interface web dans le dossier où attend le résultat de la compilation de vaultwarden :

cp -a build/ ../vaultwarden/target/release/web-vault/

Pour une mise à jour

Allez dans votre dossier vaultwarden et faites un git fetch avant le git checkout ….
Supprimez web-vault et reclonez https://github.com/bitwarden/web.git (pour éviter des manipulations avec les sous-modules git).

Ensuite suivez le tuto d’installation avec ces précautions préalables :

  • coupez le service vaultwarden
  • faites des sauvegardes de votre installation (fichiers, données de la base de données) avant de faire le rsync.

Installation

On va installer Vaultwarden dans /opt/vaultwarden et on le fera tourner avec l’utilisateur www-data :

cd ..
sudo rsync -a --info=progress2 vaultwarden/target/release/ /opt/vaultwarden/
sudo chown -R www-data: /opt/vaultwarden

Puis on va créer un service systemd, /etc/systemd/system/vaultwarden.service :

[Unit]
Description=Vaultwarden Server (Rust Edition)
Documentation=https://github.com/dani-garcia/vaultwarden
After=network.target

[Service]
# The user/group vaultwarden is run under. the working directory (see below) should allow write and read access to this user/group
User=www-data
Group=www-data
# The location of the .env file for configuration
EnvironmentFile=/etc/vaultwarden.env
# The location of the compiled binary
ExecStart=/opt/vaultwarden/vaultwarden
# Set reasonable connection and process limits
LimitNOFILE=1048576
LimitNPROC=64
# Isolate vaultwarden from the rest of the system
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
# Only allow writes to the following directory and set it to the working directory (user and password data are stored here)
WorkingDirectory=/opt/vaultwarden/
ReadWriteDirectories=/opt/vaultwarden/

[Install]
WantedBy=multi-user.target

Pour l’interface d’administration, on va créer un token avec :

openssl rand -base64 48

La configuration se fait via des variables d’environnement qu’on va mettre dans /etc/vaultwarden.env :

SIGNUPS_ALLOWED=false
WEBSOCKET_ENABLED=true
ADMIN_TOKEN=Un token généré avec `openssl rand -base64 48`
ROCKET_ADDRESS=127.0.0.1
WEBSOCKET_ADDRESS=127.0.0.1
SMTP_HOST=127.0.0.1
SMTP_FROM=vaultwarden@example.org
SMTP_PORT=25
SMTP_SSL=false

Vous remarquerez que je dis à Vaultwarden d’envoyer les mails via le serveur SMTP local. À vous de faire en sorte qu'il fonctionne. Allez voir le wiki du projet ou le modèle de fichier d’environnement pour voir quelles variables vous pourriez ajouter, enlever, modifier…

Puis :

sudo systemctl daemon-reload
sudo systemctl enable vaultwarden
sudo systemctl start vaultwarden
sudo systemctl status vaultwarden

Nginx

On installe Nginx s’il n’est pas déjà installé :

sudo apt install nginx

Configuration du virtualhost :

server {
    listen 80;
    listen [::]:80;
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name vaultwarden.example.org;

    access_log /var/log/nginx/vaultwarden.access.log;
    error_log /var/log/nginx/vaultwarden.error.log;

    ssl_certificate      /etc/letsencrypt/live/vaultwarden.example.org/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/vaultwarden.example.org/privkey.pem;

    ssl_session_timeout 5m;
    ssl_session_cache shared:SSL:5m;

    ssl_prefer_server_ciphers On;
    ssl_protocols TLSv1.2;
    ssl_ciphers 'EECDH+aRSA+AESGCM:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:+CAMELLIA256:+AES256:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!ECDSA';

    ssl_dhparam /etc/ssl/private/dhparam4096.pem;
    add_header Strict-Transport-Security max-age=15768000; # six months
    gzip off;

    if ($https != 'on') {
        rewrite ^/(.*)$ https://vaultwarden.example.org/$1 permanent;
    }

    root /var/www/html;

    # Allow large attachments
    client_max_body_size 128M;

    location ^~ '/.well-known/acme-challenge' {
        default_type "text/plain";
        root /var/www/certbot;
    }

    location / {
        include /etc/nginx/proxy_params;
        ## /etc/nginx/proxy_params contient normalement ceci :
        #proxy_set_header Host $http_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://127.0.0.1:8000;
    }

    location /notifications/hub {
        include /etc/nginx/proxy_params;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_pass http://127.0.0.1:3012;
    }

    location /notifications/hub/negotiate {
        include /etc/nginx/proxy_params;
        proxy_pass http://127.0.0.1:8000;
    }
}

Pour créer /etc/ssl/private/dhparam4096.pem :

sudo openssl dhparam -out /etc/ssl/private/dhparam4096.pem 4096

Pour le certificat Let’s Encrypt, on commente le brol relatif à ssl puis :

sudo nginx -t && sudo nginx -s reload
sudo apt install certbot
sudo mkdir /var/www/certbot/
certbot certonly --rsa-key-size 4096 --webroot -w /var/www/certbot/ --agree-tos --text --renew-hook "/usr/sbin/nginx -s reload" -d vaultwarden.example.org

Une fois qu’on a le certificat, on décommente le brol ssl puis :

sudo nginx -t && sudo nginx -s reload

Sauvegarde

Créer le script de sauvegarde /opt/backup_vaultwarden.sh :

#!/bin/bash
function vwbackup {
    DATE=$(date '+%a%H')

    # Database, ONLY FOR SQLITE!
    if [[ ! -d /opt/backup_vaultwarden/sqlite-backup/ ]]
    then
        mkdir -p /opt/backup_vaultwarden/sqlite-backup/
    fi
    echo ".backup /opt/backup_vaultwarden/sqlite-backup/db.${DATE}.sqlite3" | sqlite3 /opt/vaultwarden/data/db.sqlite3 2>> /opt/backup_vaultwarden/backup.log
    if [[ "$?" -ne "0" ]]
    then
        echo "Something went wrong with Vaultwarden database backup, please see /opt/backup_vaultwarden/backup.log on "$(hostname) | mail -s "Vaultwarden database backup" youraddress@mail.example.org
        vwbackup
    fi

    # Files
    if [[ ! -d /opt/backup_vaultwarden/files-backup/ ]]
    then
        mkdir -p /opt/backup_vaultwarden/files-backup/
    fi
    rsync -a --delete --exclude db.sqlite3 /opt/vaultwarden/data/ /opt/backup_vaultwarden/files-backup/$DATE/ 2>> /opt/backup_vaultwarden/backup.log
    if [[ "$?" -ne "0" ]]
    then
        echo "Something went wrong with Vaultwarden files backup, please see /opt/backup_vaultwarden/backup.log on "$(hostname) | mail -s "Vaultwarden files backup" youraddress@mail.example.org
        vwbackup
    fi
}
vwbackup

Puis :

sudo chmod +x /opt/backup_vaultwarden.sh
sudo mkdir /opt/backup_vaultwarden
sudo chown www-data: /opt/backup_vaultwarden
sudo apt install sqlite3

Puis, dans le cron de l’utilisateur www-data :

42 4 * * * /opt/backup_vaultwarden.sh

Logs

J’aime bien avoir mes logs dans un dossier dédié pour ce genre de service.

Dans /etc/rsyslog.d/vaultwarden.conf :

if $programname == 'vaultwarden' then /var/log/vaultwarden/vaultwarden.log
if $programname == 'vaultwarden' then ~

Dans /etc/logrotate.d/vaultwarden :

/var/log/vaultwarden/vaultwarden.log
{
        rotate 52
        dateext
        weekly
        missingok
        notifempty
        compress
        sharedscripts
        postrotate
                invoke-rc.d rsyslog rotate > /dev/null
        endscript
}

Puis :

sudo mkdir /var/log/vaultwarden
sudo chown root:adm /var/log/vaultwarden
sudo service rsyslog restart

Fail2ban

Un fail2ban qui surveille les logs, ça permet de bloquer les petits malins qui font du bruteforce

sudo apt install fail2ban

Dans /etc/fail2ban/filter.d/vaultwarden.conf :

[INCLUDES]
before = common.conf

[Definition]
failregex = ^.*Username or password is incorrect\. Try again\. IP: <HOST>\. Username:.*$
ignoreregex =

Dans /etc/fail2ban/jail.d/vaultwarden.local :

[vaultwarden]
enabled = true
port = 80,443
filter = vaultwarden
action = iptables-allports[name=vaultwarden]
logpath = /var/log/vaultwarden/vaultwarden.log
maxretry = 3
bantime = 14400
findtime = 14400

Pour la page d’admin, dans /etc/fail2ban/filter.d/vaultwarden-admin.conf :

[INCLUDES]
before = common.conf

[Definition]
failregex = ^.*Unauthorized Error: Invalid admin token\. IP: <HOST>.*$
ignoreregex =

Dans /etc/fail2ban/jail.d/vaultwarden-admin.local :

[vaultwarden-admin]
enabled = true
port = 80,443
filter = vaultwarden-admin
action = iptables-allports[name=vaultwarden]
logpath = /var/log/vaultwarden/vaultwarden.log
maxretry = 3
bantime = 14400
findtime = 14400

Finalement :

sudo service fail2ban restart

Conclusion

Voilà, vous devriez avoir un serveur Vaultwarden fonctionnel. Plus qu’à aller sur l’interface web que vous venez de mettre en place ou télécharger les clients et à les utiliser !

Pour importer vos mots de passe de Firefox, il faut passer par une application pour les exporter, puis aller dans les outils de votre client (ou de l’interface web).