Présentation

À l'heure où les sites web se multiplient et où les comptes en ligne deviennent de plus en plus obligatoires pour, par exemple, effectuer un achat ou interagir avec une communauté, il devient difficile de retenir l'ensemble des mots de passe que l'on utilise au quotidien.

Bitwarden se veut comme un coffre-fort sécurité où l'on peut enregister l'ensemble de ses informations de connexion (nom d'utilisateur, mot de passe, code OTP, etc.). Il est Open Source et propose une solution que l'on peut installer sur ses propres serveurs (auto-hébergement).

Il se démarque de la concurrence par cette dernière caractéristique surtout quand certains comme LastPass réduise à peau de chagrin leurs fonctionnalités gratuites.

C'est précisément cette dernière solution que je vais vous présenter dans cet article, tout en utilisant le fork Bitwarden_rs qui est intégralement réécrit en Rust et qui a l'avantage d'être très peu consommateur en ressources (CPU et RAM) contrairement à la version officielle, idéal donc pour une installation sur une petite configuration comme un raspberry.

Traefik sera comme toujours notre reverse proxy pour sécuriser l'accès à notre service en TLS tout en appliquant des règles strictes afin d'éviter différents types d'attaque et protéger ce dernier.

Installation

Avant de commencer

Dans le même état d'esprit que les articles précédents sur Traefik, il faut plusieurs prérequis :

  • Posséder un serveur ou un raspberry qui est accessible sur internet à travers les ports 80 et 443 (très important pour la génération de certificats via Let's encrypt) ;
  • Avoir un nom de domaine qui pointe vers votre serveur ou raspberry, et, créer un sous-domaine pour accéder à l'interface de Bitwarden ;
  • Installer docker et docker-compose sur votre serveur ou raspberry

Il reste néanmoins possible d'exécuter Traefik sur votre machine en local, mais la génération de certificats ne sera pas possible et il faudra accepter le certificat par défaut "TRAEFIK DEFAULT CERT" afin de se connecter aux différents services exposés.

Vous êtes prêt ? Allons-y !

Le code du projet que sera utilisé est disponible sur mon compte Github.

https://github.com/axinorm/traefik-bitwarden

Une fois le projet sur votre machine, il faut configurer quelques variables d'environnement car la configuration dépend de votre type de système d'exploitation et de votre architecture. Les templates fournis sont en jinja et se génèrent avec du python.

Un fichier docker-compose.yml sera généré à la fin correspondant à votre système.

Il faut dans un premier temps créer un environnement virtuel python dans lequel jinja sera installé :

virtualenv .venv
source .venv/bin/activate
pip install jinja2

En fonction de votre système d'exploitation, il est nécessaire de spécifier les trois variables ci-dessous.

Pour une configuration GNU/Linux et une architecture ARM :

export TB_SERV_OS=linux
export TB_SERV_ARCH=arm
export TB_URL_TRAEFIK=bitwarden.example.com

Pour une configuration macOS en local :

export TB_SERV_OS=macOS
export TB_SERV_ARCH=x86
export TB_URL_TRAEFIK=bitwarden.example.local

Vous pouvez maintenant générer le fichier docker-compose.yml :

python3 generate_compose_file.py

Il faut aussi définir un mot de passe pour la base de données postgres, deux fichiers sont à compléter : postgres.env avec la variable POSTGRES_PASSWORD et bitwarden.env avec la variable DATABASE_URL.

Avant de lancer, passons en revue la configuration

Traefik

Du côté de Traefik, un fichier attire particulièrement notre attention : celui où l'on va venir renforcer la sécurité de la communication entre le client et le service mis en place, dans notre cas : Bitwarden.

Voici un extrait du fichier dynamic-conf.yml où l'on peut voir que l'on a ajouté un certain nombre de headers qui permettent de renforcer la sécurité :

http:
  middlewares:
    tlsHeader:
      headers:
        SSLRedirect: true
        forceSTSHeader: true
        STSSeconds: 315360000
        STSIncludeSubdomains: true
        STSPreload: true
        browserXSSFilter: true
        contentTypeNosniff: true
        frameDeny: true
        customFrameOptionsValue: SAMEORIGIN
        featurePolicy: accelerometer 'none'; ambient-light-sensor 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; usb 'none'; midi 'none'; sync-xhr 'none'; vr 'none'
        referrerPolicy: strict-origin-when-cross-origin

Je vous conseille de jeter un coup d'oeil ici pour avoir l'ensemble des fonctions des paramètres indiqués.

De plus, dans la seconde partie, on demande à Let's Encrypt de fournir un certificat avec comme version TLS la 1.3. Ce qui peut poser des problèmes d'accès pour les machines qui ne sont pas récentes, mais évite les dernières vulnérabilités TLS. Le sniStrict quant à lui oblige le client à donner le nom de l'hôte avec lequel il tente de démarrer la liaison TLS.

tls:
  options:
    default:
      minVersion: VersionTLS13
      sniStrict: true

Bitwarden

Du côté de Bitwarden, si on prend le cas du docker-compose.yml, on peut observer les règles qui permettent d'accéder au service :

- "traefik.enable=true"
- "traefik.http.routers.bitwarden-ui.entrypoints=https"
- "traefik.http.routers.bitwarden-ui.rule=Host(`{{ url_traefik }}`)"
- "traefik.http.routers.bitwarden-ui.middlewares=tlsHeader@file"
- "traefik.http.routers.bitwarden-ui.tls=true"
- "traefik.http.routers.bitwarden-ui.tls.certresolver=http"
- "traefik.http.routers.bitwarden-ui.service=bitwarden-ui"
- "traefik.http.services.bitwarden-ui.loadbalancer.server.port=80"
- "traefik.http.routers.bitwarden-websocket.entrypoints=https"
- "traefik.http.routers.bitwarden-websocket.rule=Host(`{{ url_traefik }}`) && Path(`/notifications/hub`)"
- "traefik.http.routers.bitwarden-websocket.middlewares=tlsHeader@file"
- "traefik.http.routers.bitwarden-websocket.tls=true"
- "traefik.http.routers.bitwarden-websocket.tls.certresolver=http"
- "traefik.http.routers.bitwarden-websocket.service=bitwarden-websocket"
- "traefik.http.services.bitwarden-websocket.loadbalancer.server.port=3012"
- "traefik.docker.network=web"

Il y a donc une partie qui concerne l'interface web de Bitwarden et une autre qui permet de communiquer via les websockets. Je vous conseille cette page de wiki qui détaille plusieurs configurations possibles en fonction du reverse proxy utilisé.

Du côté du fichier bitwarden.env qui donne la liste des variables d'environnement utilisées, on retrouve :

# Activation des websockets
WEBSOCKET_ENABLED=true
# On désactive la création des nouveaux utilisateurs
SIGNUPS_ALLOWED=false
# On utilise une base de données extérieure, dans notre cas postgres
DATABASE_URL=postgresql://postgres:monMotDePasse@postgres:5432/bitwarden
# On utilise un token pour se connecter à l'interface d'administration
ADMIN_TOKEN=monAdminToken
# On spécifie un fichier de log pour le mapper dans notre conteneur à un volume (par exemple pour la gestion des accès avec fail2ban)
LOG_FILE=/data/bitwarden.log
# On donne le domaine sur lequel va tourner Bitwarden pour renforcer la sécurité
DOMAIN=admin.bitwarden.com
...

Pour avoir plus d'informations afin de générer le token admin, vous pouvez suivre ce lien, cela sert entre autres à avoir une vue globale sur la configuration de votre instance et à la gérer (invitation d'utilisateurs, verrouillage de compte, etc.).

Dans cet article, on utilise une base de données postgres pour éviter d'utiliser la base de données par défaut sqlite. C'est un choix personnel pour me simplifier l'automatisation des sauvegardes de ma base de données (j'ai plusieurs services qui sont sur du postgres).

Néanmoins la solution permet aussi d'utiliser MariaDB avec la documentation fournie ici.

Lancement du service

Une fois l'ensemble des fichiers générés, il suffit de faire la commande suivante :

docker-compose up -d

Et le service deviendra accessible à l'url indique dans la variable TB_URL_TRAEFIK.

Vous devriez arriver sur cette interface :

bitwarden-service-up

Configurer son navigateur avec le plugin

Une fois que le serveur est mis en place, vous pouvez installer le plugin officiel Bitwarden qui permettra de se connecter à votre instance. Si comme moi, Firefox est votre navigateur favori, vous pouvez suivre ce lien ici.

Dès l'installation du plugin, il apparaît dans votre navigateur, cliquez sur l'icône de Bitwarden pour le paramétrer.

bitwarden-plugin-interface-1

Puis allez sur Paramètres en haut à gauche pour spécifier l'URL de votre service.

bitwarden-plugin-parame-tres-1

Une fois configuré, il ne reste plus qu'à enregistrer ces modifications et à vous connecter.

Sécuriser sa machine

Quand on expose ce genre de service sur internet, il est important de sécuriser l'accès à Bitwarden en ajoutant des règles pour bannir des robots ou des personnes malveillantes qui essayeraient de commettre des attaques pour accéder à votre coffre-fort.

L'auteur de la solution Bitwarden_rs proprose un guide de Hardening qui est intéressant de suivre mais aussi une page consacrée à la configuration de fail2ban spécifiquement pour notre cas.

Si comme moi, vous êtes un mordu d'Ansible, vous pouvez utiliser ce rôle qui permet de configurer fail2ban sur une machine donnée (installation et paramètrage des règles).

J'utilise ces règles-là pour mon instance Bitwarden :

fail2ban_services:
  - name: bitwarden
    enabled: true
    port: 80,443,8081
    filter: bitwarden
    logpath: /var/log/bitwarden.log
    action: iptables-allports[name=bitwarden, chain=FORWARD]
    maxretry: 3
    bantime: 14400
    findtime: 14400
  - name: bitwarden-admin
    enabled: true
    port: 80,443
    filter: bitwarden-admin
    logpath: /var/log/bitwarden.log
    action: iptables-allports[name=bitwarden-admin, chain=FORWARD]
    maxretry: 3
    bantime: 14400
    findtime: 14400

Utiliser un relai SMTP pour l'envoi des emails

Afin de rendre notre service Bitwarden le plus fonctionnel possible, il est nécessaire d'ajouter un relai SMTP pour l'envoi d'email. Je vous recommande d'utiliser un service clé en main comme MailJet, qui propose une offre gratuite avec une limitation correcte (200 emails par jour).

Une fois votre compte créé, il faut ajouter ces variables d'environnement à notre fichier bitwarden.env :

...
SMTP_HOST=in-v3.mailjet.com
SMTP_FROM=<à compléter>
SMTP_PORT=587
SMTP_SSL=true
SMTP_USERNAME=<à compléter>
SMTP_PASSWORD=<à compléter>

Conclusion

Bitwarden est un outil Open Source performant, il est devenu mon coffre-fort au quotidien. Le fait de pouvoir l'héberger sur sa propre machine permet une plus grande maîtrise de ses données personnelles à condition de sécuriser l'accès à celle-ci.

J'espère que cet article vous aura permis de voir à quel point il est facile à mettre en oeuvre et vous encouragera à le faire. :)