← ブログ一覧
技術ブログ

ヘッドレスCMSのメディアを公開/非公開にする ― R2はバケット単位公開だった

平原 典彦 — Tesseraを開発しているエンジニア。ヘッドレスCMSとAI連携に関心があります。

Tesseraのメディアに「公開/非公開」を足しました。ブログの画像は公開でいいけれど、社内資料や下書きは公開したくない——というニーズに応えるためです。実装で一番の学びは、Cloudflare R2の公開モデルがS3と違うことでした。

S3の感覚:オブジェクト単位のACL

AWS S3なら、オブジェクトごとに private / public-read のACLを設定できます。だから最初は「アップロード時に非公開フラグを立てればいい」と考えていました。

R2の現実:公開はバケット単位

ところがR2は、オブジェクト単位の公開ACLを持ちません。R2で「公開」かどうかは、バケットに公開ドメイン(カスタムドメインやr2.devの公開URL)が付いているかで決まります。付いていればバケット内の全オブジェクトが公開、付いていなければ全部非公開。オールオアナッシングです。

つまり、公開ドメインを付けたバケットに置いたオブジェクトは、ACL: private を指定しても——R2はそれを公開制御に使わないので——キーを知っていれば誰でも取得できてしまう。フラグだけの「ニセ非公開」になってしまいます。

解決:2バケット+署名付きURL

そこで、こう分けました。

  • 公開バケット:公開ドメイン付き。ブログ画像などはこれまで通りR2への直リンクで配信
  • 非公開バケット:公開ドメインを付けない。ここに置いたオブジェクトはインターネットから直接は叩けず、S3の署名付きURL(短命)でのみ配信する

非公開ファイルを見るときは、認証済みの管理者に対してその都度、有効期限つき(数分)の署名付きURLを発行します。URLが拡散しても、期限が切れれば無効。実体は公開ドメインが配信できない場所にあるので、「本当に非公開」になります。

公開/非公開の切り替えは、バケット間でオブジェクトを copy+delete して移動し、DBの visibility を更新します。

落とし穴のまとめ

  • R2はオブジェクト単位の公開ACLを持たない。公開はバケット単位
  • 「非公開」は、公開ドメインを付けないバケット+署名付きURLで実現する
  • 公開ドメインを付けたバケットに置いた時点で、フラグに関係なく公開扱い

S3の常識をそのまま持ち込むとハマるポイントでした。同じくR2で公開/非公開を分けたい人の参考になれば。

ヘッドレスCMSのメディアを公開/非公開にする ― R2はバケット単位公開だった | Tessera