用Vaultwarden搭建自己的密码管理服务

前言

密码是我们在互联网上使用各种服务的时候很难绕过的一环。我们经常能听到各种各样的科普文章中告诫我们,为了保护好自己的互联网账号,密码一定要足够复杂,最好能把大小写字母、数字、特殊符号都用上。但是,复杂的密码意味着难以记忆,而当下一个普通的互联网用户很可能拥有几十个账户。为了不折磨自己的脑细胞,很多人选择给多个账户使用同一个密码。然而,由于有的网站在数据安全方面疏于防护,用户的密码遭到泄漏的事故时有发生。虽然这些密码遭到泄漏的账户可能没有很高的价值,但是却可能导致使用了同样密码的高价值账户被盗。此外,有的人还在创建复杂密码的时候还会使用自己的姓名缩写、生日、手机号等信息,这也为通过社会工程学手段破解密码提供了可能。

为了解决这一问题,密码管理服务应运而生。密码管理服务为用户提供了存储互联网账户的用户名和密码的服务,往往还会和浏览器、手机操作系统等结合,提供自动填充、自动记录等功能。在安全性方面,无论是存储在本地还是云端,都会用用户设置的密码进行加密。有了密码管理服务,我们就可以给每个互联网账户使用随机生成的强密码。最常见的密码管理服务就是Chrome、Edge等浏览器自带的密码自动填充功能和iOS、MacOS提供的系统级密码管理。我之前使用的也是Chrome的自动填充功能,但是这个功能毕竟是绑定了Chrome浏览器和谷歌账号。这就限制了浏览器的选择,比如前段时间使用Chromium内核的Edge很火,但是因为自己的互联网账号密码都保存在Chrome上,所以无法尝试。类似的,苹果的密码管理服务也不方便在Windows和Android下使用。因此我最近决定迁移到相对独立的密码管理软件上。

为什么选择BitWarden

密码管理服务的安全性来自于现代加密算法,在无法攻破加密密码的情况下是无法获得加密内容的。但是为了能够在不同的设备上使用保管的密码,我们必须依赖于云端服务。而一旦涉及到云服务,就存在着很大的不确定性,因为我们很难检查服务器上实际运行的代码。这也是我没有选择很热门的1Password的原因。

BitWarden是前后端均开源的密码管理服务器,并且还支持由用户自己搭建后端服务。当然实际中大家使用更多的是Vaultwarden(原名为BitWarden_RS)这个非官方简化版后端实现,因为它占用的资源更少。同时BitWarden的前端也有很好的跨平台支持,对主流的浏览器和操作系统都提供了支持。

如何搭建自己的Vaultwarden服务

首先用docker容器运行Vaultwarden服务

docker pull vaultwarden/server:latest
mkdir /vw-data # this is used for permanent data storage
docker run -d --name vaultwarden \
 -e WEBSOCKET_ENABLED=true \
 -v /vw-data/:/data/ \
 -p 10020:80 -p 3012:3012 \
 vaultwarden/server:latest

其中10020和3012分别是主服务和WebSocket服务的端口,/vw-data是用来保存数据的文件夹。

然后在域名服务商的管理页面添加DNS记录,将准备的域名指向服务器的IP地址。作为例子,这里假设我们准备的域名是www.example.com,服务器的IP是1.1.1.1。

然后安装certbot

apt-get install -y snapd
snap install core; sudo snap refresh core
snap install --classic certbot
ln -s /snap/bin/certbot /usr/bin/certbo

然后使用certbot进行证书生成

wget https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py
chmod +x acme-dns-auth.py # 注意要更改acme-dns-auth.py的首行的python为python3
mv acme-dns-auth.py /etc/letsencrypt/
certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d \*.www.example.com -d www.example.com

在最后一步会要求你在域名的DNS配置中添加一个CNAME项来认证你的所有权,完成之后等待DNS更新之后按下回车。如果还没有更新完成就回车的话认证会失败,可以重新运行这一命令。证书相关的文件保存在/etc/letsencrypt/live/www.example.com下面。

最后在/etc/nginx/conf.d/vaultwarden.conf中进行nginx配置(需要先安装nginx)

# Redirect HTTP to HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name www.example.com;
    return 301 https://$host$request_uri;
}

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name www.example.com;

  ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;

  # Specify SSL config if using a shared one.
  #include conf.d/ssl/ssl.conf;

  # Allow large attachments
  client_max_body_size 128M;

  location / {
    proxy_pass http://127.0.0.1:10020;
    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;
  }

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

  location /notifications/hub/negotiate {
    proxy_pass http://127.0.0.1:10020;
  }
}

然后就可以在www.example.com中访问自己的BitWarden服务了。在使用各个平台的BitWarden插件和客户端的时候,要在登陆之前先进行设置,将服务地址修改为www.example.com。

更新Vaultwarden镜像

# Pull the latest version
docker pull vaultwarden/server:latest

# Stop and remove the old container
docker stop vaultwarden
docker rm vaultwarden

# Start new container with the data mounted
docker run -d --name vaultwarden \
 -e WEBSOCKET_ENABLED=true \
 -v /vw-data/:/data/ \
 -p 10020:80 -p 3012:3012 \
 vaultwarden/server:latest

参考文献

  1. Installing Vaultwarden formally bitwarden_rs on Ubuntu 20.04 with Nginx. https://www.llewellynhughes.co.uk/post/installing-vaultwarden
  2. Vaultwarden Wiki. https://github.com/dani-garcia/vaultwarden/wiki