noellabo's tech blog

@noellaboの技術ブログ

Wasabiのパブリックアクセスが使えなくなった件(対応の仕方)

実はWasabi、2023年3月13日から、新しいアカウントではパブリックアクセス可能なバケットを作成できなくなりました。

https://docs.wasabi.com/docs/wasabi-cloud-storage-management-console-1#public-access

Public Access

New customers can no longer automatically make buckets or objects publicly accessible. If you are a new customer and are interested in allowing your objects to be publicly accessible, reach out to Wasabi Support (support@wasabi.com).

これはつまり、MastodonやMisskeyのオブジェクトストレージとして(そのままでは)使えなくなってしまったということです。なんということでしょう!

さて、どうするか。

まぁ、匿名アクセスできないことが問題なので、閲覧権限のあるユーザーとしてリクエストすればいいわけです。Authorizationヘッダにリクエストの署名をつけて呼び出すか、Query stringにパラメータとしてつける方法で対応することとします。

……なんて簡単に言いましたが、これ実際に対応するのはやっかいですよね。これまでのように、cloudflareのCNAMEで振るだけってわけにはいかないですからね……。

私はこの問題、nginx上のluaを使ってリクエストを署名するアプローチで対応することにしました。まぁたぶん、これが処理速度や負荷の面で有利なんじゃないかな。誰かの参考になるかと思いますので、ここで共有しておきます。

なお、今回オブジェクトストレージの移転を行ったfedibird.com, nightly.fedibird.comのメディアサーバーは、最前面にcloudflareによるキャッシュを置き、その後ろにリバースプロキシとしてnginxを置き、luaで署名を付加してWasabiにリクエストするという構成としました。

cloudflareは負荷軽減のためだけに存在するキャッシュなので、問題があれば外して、直接nginxにアクセスするような構成にしてもOKです。

nginxは、lua関係の機能が組み込み済みになっていて使いやすいOpenRestyをインストールし、署名の為のパッケージをOPMからインストールします。めっちゃありがたい。でもそのままではWasabiに対応していないので、そこだけちょっと変更して使います。

nginxでメディアのプロキシサーバーをたてる方法の詳細については本稿では割愛します。要点のみ記します。

手順

OpenRestyをインストールする。(ここではUbuntu 22.04)

sudo apt-get -y install --no-install-recommends wget gnupg ca-certificates
wget -O - https://openresty.org/package/pubkey.gpg | sudo gpg --dearmor -o /usr/share/keyrings/openresty.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/openresty.gpg] http://openresty.org/package/ubuntu $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/openresty.list > /dev/null 
sudo apt-get update
sudo apt-get -y install openresty

Wasabiで作成しておいたパブリックアクセスだけできるポリシーを割り当てたユーザーのaccess-keyとsecret-keyを、ユニットファイルのEnvironmentでサービスに渡します。容易に内容が漏れるので安全ではないアプローチですが、もともと全面的にパブリックアクセスさせるのが目的ですので、これが漏れても実害はないので、今回はこれでいきます。systemd-credsとか使ってみたいですねー。

sudo systemctl edit openresty.service

中身はこれ。

[Service]
Environment=AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXX
Environment=AWS_SECRET_ACCESS_KEY=XxXXXxx99XXX9xxXxXX9xxxX9xX9xxxX9xxXXxxX

GUI/lua-resty-aws-signatureをパッケージマネージャでグローバルインストールする。

sudo opm get GUI/lua-resty-aws-signature

ちょっといじりましょう。パッケージ管理とか面倒なので、まぁ直接で……。

sudo -e /usr/local/openresty/site/lualib/resty/aws-signature.lua

function get_service_and_regionのpatternsにaws用しかないので、これを追加します。wasabi用のパターンです。

{'s3%.([a-z0-9-]+)%.wasabisys%.com', 's3', nil}

nginx.confに設定追加。

sudo -e /etc/openresty/nginx.conf

直下に、取り込む環境変数を指定。

env AWS_ACCESS_KEY_ID;
env AWS_SECRET_ACCESS_KEY;

メディアサーバの設定を書いて、その中で、proxy呼び出しするlocationの中に変数設定とluaの署名処理の呼び出しを追加。必要なヘッダを定義してくれます。

location / {
  set $bucket 'bucketname';
  set $region 'ap-northeast-1';
  set $s3_host $bucket.s3.$region.wasabisys.com;

  access_by_lua_block {
    require("resty.aws-signature").s3_set_headers(ngx.var.s3_host, ngx.var.uri)
  }

  proxy_pass https://$s3_host;
  (snip...)
}

これで、権限がないって403エラーになることなく、メディアが取得できるようになればOKです。

(おまけ)オブジェクトストレージの切り替えTIPS

サービス中にオブジェクトストレージを切り替える場合、新規のデータは問題ありませんが、過去のデータを新しいオブジェクトストレージにコピーしおわるまで参照できなくなってしまう問題があります。

事前に全部コピーしておいて、同期が完了してから切り替えることもできますが、ものすごく準備に時間がかかります。

そこで、ここでは別のアプローチをとります。新しいオブジェクトストレージにアクセスしてファイルが存在しなかった場合に、古い方にアクセスを302リダイレクトする方法です。(もちろん、古い方へのアクセス手段を生かしておく必要があります)

この設定はコピーが完了すれば必要なくなりますので、頃合いをみて削除できるよう、リマインダーをセットしておきましょう。

error_page 404 /forward;
location /forward {
  internal;
  return 302 https://example.com$request_uri;
}