XF

服务部署 Step 4. Bitwarden 密码管理器

为什么使用密码管理器

Why you should use a password manager

我个人目前对密码管理的需求是:

  1. 我在大量的网站(至少 3 位数)上注册过账号;
  2. 我在同一网站上也可能由于种种原因而有不止 1 个账号;
  3. 我们不提倡「一码走天下」,因为一旦某个十八线网站的数据发生泄露,别人就可以利用其泄露的密码登录你其他网站的账号;
  4. 如果这大量的网站都使用不同的密码;
  5. 每个网站还有很多额外的账户信息,例如绑定的邮箱、手机号、安全提示问题等,还有一些银行支付类网站,登录密码、支付密码和查询密码都不一样。
  6. 有一些密码,是真正密码学意义上的密码,是一旦丢失就不可能用手机、邮箱等找回的,比如比特币钱包的密钥。
  7. 有的网站要求过一段时间就要修改密码,新密码还不能与任何曾经用过的密码相同。

这些要求导出了唯一可行的解决方案,就是使用密码管理器。

除了上述痛点外,使用密码管理器还带来了额外的好处:设计良好的密码管理器可以通过自动填充使登录网站填写密码的过程大大加快。

市面上有很多密码管理器,例如:

专门的密码管理器通常支持多字段、多条目类型,通常可以用来记录一切重要的账户资料、笔记,还有附件支持。而互联网大厂或浏览器附带的密码管理器,通常就是只记录网址、用户名、密码这 3 个简单的字段,方便自动登录(Update:2021 年 WWDC 之后的 iCloud Keychain 已经可以记录 One-Time Password)。

在上面的密码管理器中,Bitwarden 除了官方有提供一个在线服务之外,还支持自建服务(self hosted)。最近大家自建密码管理器比较流行的方案选择也是 Bitwarden。

Bitwarden_RS

Bitwarden 官方给出了一个大而全的部署脚本,这个脚本接管了大量的内容,包括 HTTPS 反向代理服务器、Portal、Notifications 通知、MSSQL 数据库等等都是独立的容器,全部部署下来大概要十几个容器,最低内存要求 2GB,推荐 4GB。我猜测这个配置是用来满足企业内部员工密码管理的需求的,对于以 1GB 乃至更小内存为主流的个人 VPS 玩家,这套系统庞大到难以接受。

好在开源社区已经有了一个 Rust 语言实现的非常轻量级的方案 Vaultwarden,而且允许我们自己部署前端的反向代理(因此可以完美融合我们前面搭建的 Traefik 基础设施),它只负责后端 Bitwarden 密码管理 API.

Update: Vaultwarden 原名 Bitwarden_RS,后因避免商标专利问题改名。是一个非官方社区使用 Rust 实现的、兼容 Bitwarden API 的客户端。即,用户可以在服务器端部署 Vaultwarden,各设备则可安装 Bitwarden 官方客户端软件直接登录。

使用 Docker 的服务端搭建过程:

创建文件目录及配置文件

注 2本文自建 Bitwarden 容器要成功运行,前提是已经完成前面文章中启动 Traefik 容器的步骤。

mkdir -p ~/site/bitwardenrs
mkdir -p ~/volumes/bitwardenrs

cd ~/site/bitwardenrs
vim docker-compose.yml
# docker-compose.yml

version: "3.5"

services:
  bitwardenrs:
    image: bitwardenrs/server:latest
    container_name: bitwardenrs
    volumes:
      - bitwardenrs:/data
    restart: always
    environment:
      - WEBSOCKET_ENABLED=true
      - TZ=Asia/Hong_Kong
    env_file:
      - .env
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.bitwardenrs.service=bitwardenrs"
      - "traefik.http.routers.bitwardenrs.rule=Host(`password.my-example.com`)"
      - "traefik.http.services.bitwardenrs.loadbalancer.server.port=80"
      - "traefik.http.routers.bitwardenrs.entrypoints=websecure"
      - "traefik.http.routers.bitwardenrs.tls.certresolver=mydnschallenge"
      - "traefik.docker.network=traefik"
      - "traefik.http.middlewares.bitwardenrs.headers.stsSeconds=311040000"
      - "traefik.http.middlewares.bitwardenrs.headers.stsIncludeSubdomains=true"
      - "traefik.http.middlewares.bitwardenrs.headers.stsPreload=true"
      - "traefik.http.routers.bitwardenrs-ws.service=bitwardenrs-ws"
      - "traefik.http.routers.bitwardenrs-ws.rule=Host(`password.my-example.com`) && Path(`/notifications/hub`)"
      - "traefik.http.services.bitwardenrs-ws.loadbalancer.server.port=3012"
    networks:
      - traefik
      - default

volumes:
  bitwardenrs:
    driver_opts:
      type: none
      o: bind
      device: ${HOME}/volumes/bitwardenrs

networks:
  traefik:
    external:
      name: traefik
  default:

这里面引用了一个外部文件 .env,里面是传递到 Bitwarden 容器的配置项,其样例文件可以在项目的 GitHub 仓库中下载到,地址

cd ~/site/bitwardenrs
wget https://raw.githubusercontent.com/dani-garcia/bitwarden_rs/master/.env.template

cp .env.template .env
vim .env

编辑里面的内容。默认情况下所有选项都是注释掉的,我们只需阅读注释,将自己需要的设置项去掉注释,然后修改即可。我只编辑了少数几行,如下:

# .env

# ...
IP_HEADER=X-Forwarded-For

# ...
# 根据注释,用 openssl rand -base64 48 新生成一个字符串作为 admin 管理界面的口令
ADMIN_TOKEN=tTVg9JsZvEece27/+1lXdC9fUVeVPuXzjUH3WmAAzATW6l55bJ+urxKlKFg31v7u

# ...
# 替换成自己的域名
DOMAIN=https://password.my-example.com

# ...
# Optional: 如果你有 Yubikey,可以参考注释去申请一个 SECRET KEY 放在这里,
# 这样之后就可以在 Bitwarden 里面启用 Yubikey 两步验证功能了
## Yubico (Yubikey) Settings
## Set your Client ID and Secret Key for Yubikey OTP
## You can generate it here: https://upgrade.yubico.com/getapikey/
## You can optionally specify a custom OTP server
YUBICO_CLIENT_ID=12345
YUBICO_SECRET_KEY=...
# YUBICO_SERVER=http://yourdomain.com/wsapi/2.0/verify

# ...
# SMTP 发件服务器设置。这里我用的是 mailgun 的服务,您可以选择用自己的邮件服务商代发邮件
# 设置了邮件发送功能,才能给网站用户发送注册认证邮件等
SMTP_HOST=smtp.mailgun.org
SMTP_FROM=[email protected]
SMTP_FROM_NAME=Bitwarden_RS
SMTP_PORT=587          # Ports 587 (submission) and 25 (smtp) are standard without encryption and with encryption via STARTTLS (Explicit TLS). Port 465 is outdated and used with Implicit TLS.
SMTP_SSL=true          # (Explicit) - This variable by default configures Explicit STARTTLS, it will upgrade an insecure connection to a secure one. Unless SMTP_EXPLICIT_TLS is set to true. Either port 587 or 25 are default.
# SMTP_EXPLICIT_TLS=true # (Implicit) - N.B. This variable configures Implicit TLS. It's currently mislabelled (see bug #851) - SMTP_SSL Needs to be set to true for this option to work. Usually port 465 is used here.
SMTP_USERNAME=[email protected]
SMTP_PASSWORD=...

启动容器,创建用户

然后直接启动容器

cd ~/site/bitwardenrs
docker-compose up -d

这个可能要等一段时间(超过一分钟),Bitwarden 容器的启动比较慢。运行

docker ps

可以看到 Up 31 seconds (health: starting) 字样。等到这个 starting 变成 healthy 就差不多了。

浏览器中访问密码管理器的地址 https://password.my-example.com,直接进入登录界面,注册一个新用户。

Bitwarden InitBitwarden Register

然后就可以登录开始使用了。建议登录进去环视四周,右上角 My Account 各个设置项都瞧一瞧,验证一下邮箱,设置一下两步验证。

由于这个密码管理器是在公网上可以访问的,为了防止滥用,我在注册完我自己的用户之后,就关闭了用户注册功能。可以进入后台管理界面

https://password.my-example.com/admin

输入刚才 .env 文件中配置的 ADMIN_TOKEN,进入后台管理界面。取消掉 Allow new signups

使用 Bitwarden 客户端和浏览器插件

我们使用客户端和浏览器插件来实现密码的自动填充功能。虽然服务端软件用的是非官方实现,但这个实现是兼容官方客户端 API 的。所以只需要按照官方网站的说明下载各个平台的客户端软件,在每个客户端或浏览器插件的登录界面点击 Settings 齿轮按钮,输入自己服务器的 URL:

Bitwarden-Login

然后输入自己的用户名(邮箱)和密码,即可开始使用。

安全性说明

自建密码管理器的安全性主要有 2 大方面,即保护密码免于泄露和免于丢失。本节试图说明两个问题:

  1. 使用 Bitwarden 等具有云存储功能的密码管理器,密码泄露和丢失的可能性有多大?
  2. 如果使用朋友或其他第三方搭建的 Bitwarden 服务器,服务器管理员能看到/不能看到我的哪些信息?

密码泄露

密码泄露就是让不该看到你密码的人看到了密码。 这一点在密码管理器的正常使用中一般不用过于担心。目前主流的密码管理器,包括 Bitwarden,都是采用本地加解密的方案,即:

Bitwarden always encrypts and/or hashes your data on your local device before anything is sent to cloud servers for storage.

因此,从原理上来讲(By design),服务器的管理员对你的密码是 zero-knowledge: The server knows nothing about your passwords. 因此,即使黑客入侵了服务器拿走了服务器上的所有数据,也只是一堆解不开密文而已。

不过一些看上去不那么私密的信息,管理员确实还是能看到的:例如 Bitwarden_rs 服务器的管理员可以看到每个用户的邮箱、密码项目总数及附件的数量:

Bitwarden-Admin-Panel

另外,用户设定的对 Master Password 的密码提示(Password Hint),在数据库中是明文的。用户忘记 Master 密码时,可以申请邮件找回密码提示(但不可能直接申请找回 Master Password,因为服务器根本不会存储 Master Password)。

建议的安保措施

当然,即使正常使用时密码泄露的风险很小,您还是应该尽可能养成如下良好习惯:

密码丢失

密码丢失就是该看密码的人(你本人)无法看到密码。要避免数据丢失,需要服务器管理员尽量做足数据备份保障工作。Bitwarden_rs 的数据目录组成非常简单,需要备份的主要就是一个数据库 db.sqlite3(里面包含所有用户信息和用户的密码)和一个附件文件夹 attachments,其他的东西丢了不会造成致命损失,顶多就是被强行登出了而已,再自行登录回去就行。备份的相关说明在此

目前我自己搭建的服务器,使用 cron 任务定期将这些关键文件备份到其他至少 3 个地方,包括我的其他云服务器、腾讯云的对象存储服务,这些云服务器和对象存储服务属于不同国家的云服务商(如腾讯云、AWS、Azure),位于不同的地理区域(如北美、香港、中国内地)。

如果是使用自建或朋友自建的 Bitwarden 服务,以上备份方案都是建立在「管理员尽心尽力保护大家的数据」的基础上。您需要信任服务器的管理员有基本的技术能力和责任心,且管理员本人身体健康。