vaultwarden + Cloud Run + Litestreamで作る小規模向けパスワードマネージャ

## 背景
[vaultwarden](https://github.com/dani-garcia/vaultwarden)というパスワードマネージャ[bitwarden](https://bitwarden.com/ja-jp/)の非公式リポジトリがあります。ぶっちゃけ個人利用していたら普通にbitwardenで十分なのですが、やっぱりパスワードをクラウドで暗号化されていて、取り出しはできないといっても向こう側にデータがあるのが嫌だなぁって思ったりします。ということでセルフホストするんですが、個人でセルフホストするならば、vaultwarden+tailscale+GCE(無料枠)で構築した方がお財布に優しいです。

ですが、なぜCloud Runで構築するか？

それは以下の内容に当てはまれば、もしかしたらCloud Runでの構築を一考しても良いかもしれません。
1. すでにGCEの無料枠を使い切っている
1. 小規模なので常時稼働するほどのリソースが必要ではない
1. 構築するのにお金がかかるのが嫌（GCEってインスタンス起動したらお金かかりますもんねぇ）

私はすべて当てはまりました…

## 方針
というわけでCloud Runで作るのはいいがそもそも、vaultwardenで利用しているDBは何だろう？と調べた結果、デフォルトSQLiteではないか！？
ということで前回紹介した「[label-studio + Cloud Run + Litestreamで作る小規模向けアノテーションツール](https://qiita.com/hide_seki/items/f18a6b4d788738b3f8e4)」で使ったLitestreamでのSQLiteのレプリケーションが使えるので、この記事をそのままvaultwardenに適用してみました。
もちろん構築にはCloud ShellおよびCloud Shellエディタを利用するので、構築費用も無料。なんてお財布に優しい。

では、実際にやっていきましょう。

## カスタムvaultwardenイメージの作成
以下の順番通り実施することで、カスタムvaultwardenイメージを作成しました。
### Google Cloudコンソールの立ち上げ
ブラウザ経由で進めてもいいが、ターミナルソフトで立ち上げるのが気に入っているので以下のコマンドでGoogle Cloudコンソールを起動する
```shell
gcloud cloud-shell ssh --authorize-session
```

### vaultwardenのソースを取得
以下のコマンドでソースを取得する
```shell
git clone https://github.com/dani-garcia/vaultwarden.git
```

### Cloud Shell エディタを起動する
[マニュアル](https://cloud.google.com/shell/docs/launching-cloud-shell-editor?hl=ja)参照の上、起動する

### vaultwardenの導入
ターミナルの作業です。
以下のコマンドで必要なファイルを作成します。
```bash
cd vaultwarden
cd src
mkdir new
cd new
touch litestream.yml
touch entrypoint.sh
```
これで以下のようなディレクトリ構成になると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846192/786e7428-a5ea-984d-d8d9-bf5d76103545.png)


ここからはCloud Shell エディタ上の作業です。
まずlitestream.ymlを以下のように編集します。
```litestream.yml
dbs:
  - path: /data/db.sqlite3
    replicas:
      - url: gcs://[Google Cloud Storageのバケット名]/[保存したいフォルダ名]
```

次に、litestream経由でvaultwardenを起動するシェルスクリプトentrypoint.shを編集します。
```entrypoint.sh
#!/bin/bash
set -e

if [ -f /data/db.sqlite3 ]; then
  echo "rm old file"
  rm /data/db.sqlite3
fi

echo "exec litestream restoring"
litestream restore -if-replica-exists -config /etc/litestream.yml /data/db.sqlite3

# Litestreamによってレプリケーションしながら、アプリケーションを起動する
echo "exec litestream"
exec litestream replicate -exec "/start.sh" -config /etc/litestream.yml
```

gitクローンによって取得したvaultwardenディレクトリ内にあるDockerfileを以下のように修正する。
```shell
　：
(省略)
　：
### =====================================================
# 以下のROCKET_PORTを80から8080に変更する
### -----------------------------------------------------
ENV ROCKET_PROFILE="release" \
    ROCKET_ADDRESS=0.0.0.0 \
    ROCKET_PORT=8080 \
    DEBIAN_FRONTEND=noninteractive
### -----------------------------------------------------
　：
(省略)
　：
VOLUME /data
### =====================================================
# 以下のEXPOSEを80から8080に変更する
### -----------------------------------------------------
EXPOSE 8080
### -----------------------------------------------------

# Copies the files from the context (Rocket.toml file and web-vault)
# and the binary from the "build" stage to the current stage
WORKDIR /

COPY docker/healthcheck.sh docker/start.sh /

### =====================================================
# 以下の部分を追加
### -----------------------------------------------------
ADD https://github.com/benbjohnson/litestream/releases/download/v0.3.13/litestream-v0.3.13-linux-amd64.tar.gz /tmp/litestream.tar.gz
RUN tar -C /usr/local/bin -xzf /tmp/litestream.tar.gz
COPY --chmod=755 src/new/entrypoint.sh /usr/bin/entrypoint.sh
COPY src/new/litestream.yml /etc/litestream.yml
### =====================================================
　：
(省略)
　：
### =====================================================
# 以下の部分を変更
### -----------------------------------------------------
#CMD ["/start.sh"]
CMD ["/usr/bin/entrypoint.sh"]
### =====================================================
```

### Dockerイメージファイルの作成
カレントディレクトリを/vaultwardenに移動し、以下のコマンドを実行しDockerイメージを作成する
```shell
docker build -f Dockerfile -t vaultwarden .
```

## ArtifactRegistryへの登録
### リポジトリ作成
Google CloudコンソールからArtifactRegistryに移動しvaultwardenのリポジトリを登録する

### （必要に応じて実行）リージョンasia-northeast1のDockerリポジトリに対する認証を設定
以下のコマンドを実行し、Dockerリポジトリに対する認証設定をする。
```shell
gcloud auth configure-docker asia-northeast1-docker.pkg.dev
```

### タグ付け
ビルドしたDockerイメージに対してArtifactRegistry用にタグ付けをする。
以下のコマンドを実行し、作成したDockerイメージのIMAGE IDを取得する
```shell
docker image list

REPOSITORY     TAG       IMAGE ID       CREATED          SIZE
vaultwarden   latest    5064a45a61ea   16 seconds ago   250MB
※上記「docker image list」の出力結果はイメージです。
```

そのIMAGE IDを用いて以下のコマンドでタグ付けをする。
```shell
docker tag 5064a45a61ea asia-northeast1-docker.pkg.dev/[GCPのプロジェクト名]/vaultwarden/202407261200

docker tag [IMAGE ID] [ArtifactRegistryの場所]/[GCPのプロジェクト名]/[リポジトリ名]/[リポジトリで利用するイメージ名]
```

### ArtifactRegistryへ登録
タグ付け後、以下のコマンドでArtifactRegistryに登録する。
```shell
docker push asia-northeast1-docker.pkg.dev/[GCPのプロジェクト名]/vaultwarden/202407261200
```

## CloudRunのデプロイ
以下のコマンドで直接Cloud Runサービスを立ち上げることができる。
```shell
gcloud run deploy vaultwarden --image asia-northeast1-docker.pkg.dev/[GCPのプロジェクト名]/vaultwarden/202407261200:latest

gcloud run deploy [リポジトリ名] --image [ArtifactRegistryの場所]/[GCPのプロジェクト名]/[リポジトリ名]/[リポジトリで利用するイメージ名]:[tag]
```


## GCPのアクセス権関係の付与
CloudRunで動作するvaultwardenサービスはlitestream.ymlで設定したGCSにアクセスするため、デプロイ後にGoogle Cloudコンソール上でCloudRunサービスにアクセスし、YAML内のserviceAccountNameからサービスアカウント名を確認し、そのサービスアカウントに対して権限を付与する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846192/440daccb-2d1a-f000-61f6-dcedcd55b2c3.png)
```サービスアカウントに付与した権限リスト.
storage.buckets.get
storage.buckets.getIamPolicy
storage.buckets.update
storage.objects.create
storage.objects.delete
storage.objects.get
storage.objects.getIamPolicy
storage.objects.list
storage.objects.update
resourcemanager.projects.get
resourcemanager.projects.list
storage.managedFolders.get
storage.managedFolders.list
```

## カスタムドメインでの運用
以下CloudRunサービスにある統合で「インテグレーションを追加」を押して「カスタムドメイン-Google Cloud Load Balancing」を選択する。あとは追加したいドメインを記述して作成することで、カスタムドメイン接続に必要な情報が生成されるので、それを利用する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846192/06028310-d099-dec3-818f-1841c282645b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846192/8a87acee-1d9e-52ce-7c5f-f5d3318c0b1e.png)

カスタムドメインの設定後はLoad BalancerやCloud ArmorやIAPを設定すれば必要最低限のネットアクセスが可能なのでセキュアなサイト構築ができるので、そこは環境に合わせて設定するように。


## その他設定
以下の設定は忘れずに
1. インスタンス数の最大を1にする
1. litestreamが動作しているか、GCSを確認する
    1. ユーザを作成してから見に行くと良い
1. インスタンス数が0になってから再度アクセスし、litestreamのレストアが機能していることを確認する
1. 必要に応じてCloud Runのスペックを変更する（私はとりあえずデフォルトで動かして、ログを見て調整する予定）