Cloudflare Zero TrustとVaultwardenでパスワード管理やってみた

## はじめに
初心者のやってみた記事です。
元々はパスワードマネージャーでSAMLとかSCIMを使いたくて、Bitwarden Enterpriseプランを最低購入数の２シート分契約していました。
が、円安でお値段が辛くなってきたので、代わりにVaultwardenをセルフホストし、Cloudflare Zero Trustでアクセス出来るようにしたという良くある話です。
Cloudflare Zero Trustのセットアップ等は他に分かり易い記事があると思いますので、深く触れていません。
実質ポエムです。。

12/16 追記
当たり前なのですが、Cloudflare AccessでブラウザSSH&オートログインを行い、その後suする時に、パスワードマネージャーのブラウザアドオンでパスワード投入ができるので、かなり良い体験ができています。
AccessでSSHを許可してクレデンシャルはTermiusで集中管理でも良いですが、今回の組み合わせはオススメですね。。


### Cloudflare Zero Trust
Cloudflare Zero TrustのAccessを使用すれば、オンプレサーバなどのクローズドな環境に対して、インバウンドの許可ルールなしに通信するすることができるようになります。
ZscalerのPrivate Accessと同じような仕組みですね。
Accessの経路にGatewayをかませることもでき、柔軟な設定ができそうです。

50ユーザまでなら無料で使用できるというのは有り難い話です。
（快適で有り難すぎます。。個人利用で少額ながらお布施をしたい気持ちです。）

https://www.cloudflare.com/ja-jp/products/zero-trust/zero-trust-network-access/


### Vaultwarden
Bitwardenでもセルフホストはできますが滅茶苦茶リソースを食いそうなので、非公式Rust実装であるVaultwardenを使わせていただきました。
軽量なので、VPSやクラウドVMの最安プランで運用できると思います。
Bitwarden APIについて一通りの実装がされており、Yubi Keyなども扱えるので有り難い限りです。
本家キレないのかなとか思ったりしますが、使えるうちは使おうと思います。。

https://github.com/dani-garcia/vaultwarden


## Cloudflare Registrarでドメイン登録
基本的にCloudflare Access経由でVaultwardenに接続しますが、非常時にインターネットでもアクセス出来るようにしたいと考え、Cloudflare Registrarでドメインを登録することにしました。
共用とはいえ無料の証明書を使用できますし、セキュリティの設定も細かく出来るので、運用もこちらでしています。

https://www.cloudflare.com/ja-jp/products/registrar/



## デプロイ
### VPSの展開
セルフホスト環境でいちいちVPC設定とかインバウンドのポリシーを書きたくなかったので、VPSを選定しました。
価格性能比が良い気がしますので、いつもConoha VPSを使用しています。
HTTP/HTTPSのポート開けを１クリックで許可したりできますし、何かと楽です。。
特にディストリビューションにこだわりはなかったので、標準で用意されているDockerイメージ(Ubuntu)を使用しました。

https://www.conoha.jp/vps/

### Cloudflare ドメイン設定
VPSでグローバル固定IPアドレスが払い出されましたので、Cloudflareのドメイン管理でAレコードとAAAAレコードを設定します。
Cloudflare Accessを設定すると、ここにCNAMEも追加されます(後続)

### Cloudflare Accessで作業用にSSHの設定
CloudflareのトンネルCloudflaredの機能にブラウザでのRDP/SSHがサポートされましたので、以後の構築はこちらでするようにしました。
構築段階でSSHポートも開けなくていいとは、何て有り難いんだ。。
作業端末のWarpクライアントで認証しているユーザ名AとCloudflaredが動いているアクセス対象サーバのユーザ名Aが一致していれば、URLを叩いた瞬間にユーザAでSSHログインさせることもできます。楽。
軽快に動きますし、コピペも動作するのでこれで十分です。iPhoneとかiPadでメンテもし易くなるかなぁ。。

https://developers.cloudflare.com/cloudflare-one/applications/non-http/#rendering-in-the-browser

### Vaultwardenをデプロイ
下記のような設定でDocker Composeでデプロイしました。

```docker-compose.yml
version: '3'
services:
  nginx-proxy:
    image: jwilder/nginx-proxy
    container_name: nginx-proxy
    privileged: true
    ports:
      - "80:80"
      - "443:443"
    environment:
      - TZ=Asia/Tokyo
      - TRUST_DOWNSTREAM_PROXY=false
    volumes:
      - ./nginx/certs:/etc/nginx/certs:ro
      - ./nginx/conf:/etc/nginx/conf.d
      - /var/run/docker.sock:/tmp/docker.sock:ro
    restart: always

  vaultwarden:
    image: vaultwarden/server
    container_name: vaultwarden
    environment:
      - TZ=Asia/Tokyo
      - SIGNUPS_ALLOWED=false
      - INVITATIONS_ALLOWED=false
      - WEBSOCKET_ENABLED=true
      - SHOW_PASSWORD_HINT=false
      - YUBICO_CLIENT_ID=00000
      - YUBICO_SECRET_KEY=**********
      - VIRTUAL_HOST=vault.contoso.com,local-vault.contoso.com,local-int-vault.contoso.com
      # vault(インターネット用)、local-vault(Cloudflare Access用)、local-int-vault(Cloudflare Access内部参照用)
      - VIRTUAL_PORT=80
    volumes:
      - /home/vaultwarden/vw-data:/data
    ports:
      - "33545:80"
    restart: always
    depends_on:
      - nginx-proxy
```

VaultwardenでのHTTPS実装はRocket Frameworkを使用している関係で制限があるそうなので、前段にNGINXのリバースプロキシを置くことにしました。
https://github.com/dani-garcia/vaultwarden/wiki/Enabling-HTTPS

Cloudflare Accessでも独自ドメインのCNAMEでHTTPSアクセスしたかったので、内部参照用にVIRTUAL_HOSTを追加したりしました。
他に良いやり方無かったかなぁ。。



## Cloudflare Accessの設定
### Tunnel設定でちょっとハマった所
Access経由で接続するHostname(ドメインのネームサーバでCNAMEが設定される)と内部で参照するターゲットのサービスを設定します。
サービスのURLは通常'localhost:443'で良いと思いますが、CloudflareとVPS間のSSL/TLS接続モードをフル（厳密）にする関係で、色々試行錯誤していたら、Access経由の接続用と別にサービス用のホスト名を用意するという奇妙な感じになってしまいました。サーバ内ではHostsで名前解決しています（どうにかしたい）

![2023-12-10_22-19-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214430/003bef25-dc3b-4562-fb55-d9b12f3a0f3b.png)



## Cloudflare Webサイトのセキュリティ設定
インターネット経由の接続用に取得したドメインのセキュリティ設定をしていきます。

### SSL/TLS - 概要
全ての経路で暗号化したいのと、細かくセキュリティ設定できるようになるので、フル（厳密）に設定します。
![Cloudflare_SSL.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214430/9e0ad9f0-f6ef-730f-bdc7-8b44e7bea216.png)

### SSL/TLS - 証明書の生成とダウンロード
HTTPSで接続するために使用するエッジ証明書と、Cloudflare - VPS間の通信を暗号化するためのオリジン証明書をdocker-compose.ymlで指定したディレクトリに配置して、docker composeで再起動します。

### セキュリティ - WAF
他のサイトもあるのでサーチエンジンも許可していますが、脅威スコアの高い or 国外からのトラフィックをブロックすることにしました。ブロックしまくっていたら大分落ち着いてきました。
(一時24時間で死ぬほどトラフィック来てて、インターネット怖いってなりました。。)
ｍTLSを使って証明書認証&証明書がない場合のブロックもできるみたいなので、今後はこちらも試してみたいです。

![Cloudflare_WAF.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214430/88be7325-c0f6-b7a9-3b54-dd4f8cc49b3e.png)



## 接続
これで下記のようなURLで接続する構成を作ることができました。
- Cloudflare Access経由： https://local-vault.contoso.com/
- インターネット経由： https://vault.contoso.com/

![Vaultwarden Web.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214430/7494a84d-7102-e4a1-9c6d-3579adf7eadf.png)

緊急時にインターネット経由で接続する場合のみ、普段は完全に閉じているポートを解放するようにします。

![2023-12-10_22-34-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214430/008906c8-52ee-1814-0eb4-bb56a9486657.png)



## 感想
Cloudflare Zero Trustもdockerも、そもそもWEB系のインフラも詳しいことは知らないのですが、基本はクローズド環境に接続できるようにし、緊急時はインターネットでも繋げられるようにするという目的は何とか達成できたようです。Cloudflare様様やで。

あと今までCloudflare Tunnelは専用のサーバを立てて、背後にあるネットワークを繋げるようにしていましたが、ブラウザSSHがあまりにも快適すぎて、全てのサーバにcloudflaredをインストールしてしまおうかと思ったりしました。恐ろしいで。