self-hosted Bitwarden Server

Was ist Bitwarden

Für alle die Bitwarden noch nicht kennen:

Es handelt sich hierbei um einen quelloffenen Passwort-Manager, der mittels Ende-zu-Ende-Verschlüsselung Passwörter speichert, synchronisiert und per Webinterface, aber auch vielen Apps und Browsererweiterungen bereitstellt. Ohne Master-Kennwort verliert man den Zugang zum Passwortspeicher und Serverbetreiber können Kennwörter auch nicht auslesen. Zusätzlich kann ein Eintrag für mehrere Apps und Webseiten gelten, indem man durch Regeln festlegt, wofür der Eintrag verwendet werden darf. Ein Beispiel:

Ihr nutzt die Nextcloud-App, aber auch das Webinterface. So kann in Bitwarden ein gemeinsamer Login für die Webseite https://meine.nextcloud.com, aber auch die App com.nextcloud.client hinterlegt werden. Bitwaren bietet beim automatischen Ausfüllen die Speicherung der URL an. Viele Firmen nutzen auch multiple Dienste mit LDAP mit einem gemeinsamen Login, diese können ebenfalls abgebildet werden.

Für Logindaten mit Zertifikaten bietet Bitwarden die Speicherung von Dateianhängen an und jedem Datensatz können weitere Klartext, aber auch verdeckte Zusatzfelder, die man selbst benennen kann, hinzugefügt werden.

Grundsätzlich kann man Bitwarden als den Passwort-Manager schlecht hin bezeichnen, da man seine Daten selbst hosted und mit den vielen Zugriffsmöglichkeiten endlich eine Lösung für alle gängigen Geräte hat.

Und braucht man für die 2-Faktor-Authentifizierung einen OTP-Generator, dann kann Bitwarden auch das übernehmen …
Aber genug der einleitenden Worte, auf zur Installation, basierend auf Docker.

Vorbereitung

Eine grundlegende Anleitung findet man direkt beim Hersteller, wobei in dieser Anleitung leichte Anpassungen vorgenommen werden: https://bitwarden.com/help/install-on-premise-linux/.

Zunächst legen wir die Struktur an, der Ordner kann frei gewählt werden:

# Ordner anlegen und betreten
mkdir -p /srv/docker/bitwarden
cd /srv/docker/bitwarden

# lädt das Verwaltungsskript von Bitwarden runter
curl -Lso bitwarden.sh https://go.btwrdn.co/bw-sh && chmod 700 bitwarden.sh

Dann wird Bitwarden installiert (Images gepullt, Verzeichnisse angelegt):

cd  /srv/docker/bitwarden
./bitwarden.sh install

Wärend der Installation werden verschiedene Fragen gestellt:

# Hier wird die Domain für den Aufruf festgelegt
Enter the domain name for your Bitwarden instance (ex. bitwarden.example.com): bitwarden.mydomain.com

# Let's Encrypt lassen wir vom vorgelagerten Nginx regeln, daher nein
Do you want to use Let's Encrypt to generate a free SSL certificate? (y/n): n

# Datenbankname, kann Standard bleiben, einfach Enter
Enter the database name for your Bitwarden instance (ex. vault): <ENTER>

# die Installations-ID & der Key die vorher beschafft wurde (siehe oben)
Enter your installation id (get at https://bitwarden.com/host): xxxxxxxxxxx
Enter your installation key: xxxxxxxxxxxx

# wir nutzen ein selbstsigniertes Zertifikat, was Bitwarden anlegen wird, daher hier nein auswählen
Do you have a SSL certificate to use? (y/n): n
# ja bitte!
Do you want to generate a self-signed SSL certificate? (y/n): y

Generating key for IdentityServer.
Generating a RSA private key
...................++++
writing new private key to 'identity.key'
-----

!!!!!!!!!! WARNING !!!!!!!!!!
You are not using a SSL certificate. Bitwarden requires HTTPS to operate.
You must front your installation with a HTTPS proxy or the web vault (and
other Bitwarden apps) will not work properly.


# Da wir einen eigenen nginx mit SSL Zertifikat für den öffentlichen Zugriff verwenden, benötigt Bitwarden kein LE, oder gar ein öffentliches Zertifikat. Es reicht daher aus, bei der Bitwarden # Installation ein eigenes Zertifikat generieren zu lassen. Die Kommunikation zwischen Bitwarden und dem eigenständigen nginx wird somit dennoch verschlüsselt durchgeführt.
# Ohne Zertifikats wäre es eben HTTP anstatt HTTPS und somit innerhalb des Servers unverschlüsselt...

Konfiguration

Hinweis

Die Mailkonfiguration ist nötig um Zugang zum Admininterface zu erhalten.
Für jeden Zugriff wird ein einmalig gültiger Link per E-Mail verschickt!

Der Bitwarden-Installer hat nun eine Verzeichnisstruktur angelegt und wir können weitere Konfigurationen vornehmen:

#File: /srv/docker/bitwarden/bwdata/config.yml

# Wir sorgen dafür, dass Bitwarden sich nicht auf Port 80 und 443 bindet, da hier bereits ein Webserver lauscht. Deswegen binden wir den Docker-Proxy der von Bitwarden vorgesehen ist, auf eine eigene IP-Adresse mit Port 8080 und 8443.

http_port: 172.16.1.1:8080
https_port: 172.16.1.1:8443

Datei: /srv/docker/bitwarden/bwdata/env/global.override.env

globalSettings__mail__replyToEmail=no-reply@bitwarden.mydomain.com
globalSettings__mail__smtp__host=REPLACE
globalSettings__mail__smtp__port=587
globalSettings__mail__smtp__ssl=false
globalSettings__mail__smtp__username=REPLACE
globalSettings__mail__smtp__password=REPLACE

# Hier müssen die SMTP-Auth Daten und die gewünschte E-Mailadresse hinterlegt werden, zum Beispiel:

globalSettings__mail__replyToEmail=no-reply@bitwarden.mydomain.com
globalSettings__mail__smtp__host=smtp.google.com
globalSettings__mail__smtp__port=465
globalSettings__mail__smtp__ssl=true
globalSettings__mail__smtp__username=myaccount@gmail.com
globalSettings__mail__smtp__password=super_tolles_pasword

Im späteren Verlauf kann man, nachdem ein Account angelegt wurde, die Registration für Außenstehende deaktivieren.

globalSettings__disableUserRegistration=true

Dies ist aber erst sinnvoll, wenn alle Accounts eingerichtet wurden die man benötigt ;)

Nach Anpassungen in den oben genannten Dateien müssen die Docker-Files neu genriert werden:

./bitwarden.sh rebuild

Weil wir eine feste IP-Adresse für den Bitwarden-Nginx und seine Dienste möchten, bietet es sich an, Docker mitzuteilen, dass ein bestimmtes Netz gewünscht wird. Dies lässt sich über eine sogeannte override-Datei regeln. Diese ist im Standardfall noch nicht existent und muss angelegt werden!

# File /srv/docker/bitwarden/bwdata/docker/docker-compose.override.yml
---
version: '3'

services:
  nginx:
    networks:
      default:
        ipv4_address: 172.16.1.250

networks:
  default:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.16.1.0/24
    driver_opts:
      com.docker.network.bridge.name: br_bitwarden

Hiermit wird sichergestellt, dass der nginx-Container die IP-Adresse 172.16.1.250 erhält und man über diese den Dienst erreicht. Andernfalls könnte Docker die IP-Adressen der Container nach und nach neu würfeln und man bekommt keine konsistente Konfiguration für den vorgelagerten Nginx.

Start und Test

Nun kann man Bitwarden starten und die interne Erreichbarkeit testen:

./bitwarden.sh start

# -k weil selbstsigniertes Zertifikat
curl -k https://172.16.1.250:8443
<!doctype html>......

Erhält man eine Antwort, kann nun der vorgelagerte Nginx konfiguriert werden. Je nach lokalen gegebenheiten kann dies sehr unterschiedlich passieren, gehen wir mal vom Standardfall (Ubuntu, Archlinux) aus…

Nginx und Bitwarden verbinden

# File: /etc/nginx/sites-enabled/bitwarden.mydomain.com.conf

# Dieser vHost nimmt auf Port 80 alle Anfragen an und leitet diese auf HTTPS um, außer Let's Encrypt ACME Challenges.
server {
    server_name     bitwarden.mydomain.com;

    listen          *:80;

    # Dies ist sehr individuell, mehr dazu im Bereich Let's Encrypt
    location ~ .well-known {
        root        /srv/www/letsencrypt/;
    }

    location / {
        return  301 https://$host$request_uri;
    }
}

Danach den Ordner für die LE Validierung anlegen und den Nginx neustarten / reloaden:

mkdir -p /srv/www/letsencrypt/
nginx -t && nginx -s reload

Let’s Encrypt Zertifikat anfragen

Hier wird nun der DNS-Eintrag benötigt, dieser wird nämlich öffentlich abgerufen. Wenn er noch nicht existiert, ist spätestens nun der richtige Zeitpunkt. Der Certbot legt eine ACME-Challenge-Datei unterhalb von /srv/www/letsencrypt an.

certbot certonly --webroot -w /srv/www/letsencrypt/ --email admin@mydomain.com --non-interactive --agree-tos -d bitwarden.mydomain.com

Nun ergänzen wir die Konfiguration mit dem HTTPS Host, weil das SSL-Zertifikat vorliegt und ein Reload keinen Fehler mehr produziert:

# File: /etc/nginx/sites-enabled/bitwarden.mydomain.com.conf

# Dieser bereich sollte erst eingerichtet werden, wenn ein SSL Zertifikat vorliegt! 
server {
    server_name         bitwarden.mydomain.com;

    listen              *:443 ssl;

    access_log          /var/log/nginx/bitwarden.mydomain.com.access.log;
    error_log           /var/log/nginx/bitwarden.mydomain.com.error.log;
    rewrite_log         on;

    # Platzhalter, alle Anfragen werden sowieos an Bitwarden geleitet
    root                /srv/www/default;
    index               index.php index.html index.htm;

    ssl_certificate     /etc/letsencrypt/live/bitwarden.mydomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/bitwarden.mydomain.com/privkey.pem;

    client_max_body_size 1024M;

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    location / {
        # die IP-Adresse ist nun statisch, da wir diese im docker override hinterlegt haben...
        proxy_pass  https://172.16.1.250:8443$request_uri;

        proxy_redirect off;
        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_set_header X-Forwarded-Protocol $scheme;
        proxy_set_header X-Url-Scheme $scheme;
    }
}

Danach noch einmal den nginx reloaden:

nginx -t && nginx -s reload

Im Anschluss sollte Bitwarden öffentlich erreichbar sein (Adresse ist ein Beispiel!):

https://bitwarden.mydomain.com

Sofern die Mailkonfiguration korrekt ist, dürfte eine Registrierung auch klappen. Diese kann im Anschluss wie bereits erwähnt deaktiviert werden (siehe oben). Ein rebuild ist dann nötig, wodurch die Container neugestartet werden.

Viel Erfolg und Spaß mit Bitwarden ;)

Updates

Möchte man Bitwarden updaten:

cd /srv/docker/bitwarden
./bitwarden.sh update