なぜ「署名付きURL」が必要なのか
S3に置いた動画や資料を、お金を払ったユーザーだけに見せたい。よくある要件だ。
S3バケットを非公開にすればいい? それだとCloudFront経由でも配信できなくなる。CloudFrontを公開すれば誰でもアクセスできてしまう。つまり「CDNで高速配信したいが、見せる相手は制限したい」という矛盾が生まれる。
署名付きURLは、この矛盾を**「URLそのものに入場券を埋め込む」**というアプローチで解決する。
身近なたとえ: 映画の前売り券
映画館で例えると、こういうことだ:
- 映画館(CloudFront)は誰でも入れる場所にある
- だが上映室のドアには鍵がかかっている(S3は非公開)
- 前売り券(署名付きURL)を持っている人だけが入れる
- 前売り券には「3/7の19時の回まで有効」と書いてある(有効期限)
- 前売り券にはスタッフだけが読める偽造防止マーク(デジタル署名)がある
ポイントは、映画館側は「誰がチケットを買ったか」を知らなくていいこと。チケットが本物かどうかだけ確認すれば済む。これが署名付きURLの設計思想だ。
S3の署名付きURLとの違い
「署名付きURL」はS3にもある。混同しやすいので整理する。
共通する本質:
- どちらも「URLに一時的なアクセス権を埋め込む」仕組み
- 有効期限がある
- 秘密情報(鍵)を使って署名する
CloudFront版ならではの特徴:
| S3署名付きURL | CloudFront署名付きURL | |
|---|---|---|
| 署名者 | IAMユーザーのアクセスキー | RSA秘密鍵(自分で管理) |
| 配信元 | S3のエンドポイント直接 | CloudFrontエッジ(CDN) |
| 速度 | リージョンに依存 | エッジから配信(高速) |
| 制御 | URL・期限のみ | URL・期限・IP制限・カスタムポリシー |
つまりCloudFront版は「CDN配信 + きめ細かいアクセス制御」を両立させたもの。S3版の上位互換と考えていい。
全体像: 3つのフェーズ
署名付きURLの仕組みは、大きく3つのフェーズに分かれる。
フェーズ1: 鍵の準備(事前に一度だけ)
公開鍵暗号を使う。映画館のたとえでいう「偽造防止マークの仕組みを作る」段階。
- 管理者がRSA鍵ペアを生成する(秘密鍵 + 公開鍵)
- 秘密鍵は自分で安全に保管する(チケットに署名するための印鑑)
- 公開鍵はCloudFrontに渡す(偽造防止マークを検証するための情報)
なぜRSAか? 署名する場所(アプリサーバー)と検証する場所(CloudFront)が別だから。秘密鍵を渡さずに検証できる公開鍵暗号が必要になる。
フェーズ2: URLの発行(リクエストのたびに)
ユーザーがコンテンツにアクセスしたいとき、アプリケーションサーバーが署名付きURLを生成する。
- ポリシーを作る — 「このURLに、この期限まで、このIPからアクセスOK」というJSON
- ポリシーをハッシュ化 — SHA-1でダイジェストを作る
- 秘密鍵で署名 — ダイジェストをRSAで暗号化(=デジタル署名)
- URLに全部くっつける — 元のURL + 署名 + キーID + 期限 = 署名付きURL
できあがったURLはこんな形になる:
https://d1234.cloudfront.net/video.mp4
?Expires=1686873600
&Signature=ABCxyz...(Base64エンコードされた署名)
&Key-Pair-Id=KPID1234
フェーズ3: アクセスと検証(ユーザーがURLを使うとき)
- ユーザーが署名付きURLにアクセスする
- CloudFrontがURLのパラメータを読む
Key-Pair-Idから対応する公開鍵を取得- 公開鍵で署名を検証(改ざんされていないか確認)
- ポリシーの条件を確認(有効期限内か、IPは合っているか)
- すべてOKなら → S3からコンテンツを取得して配信
- NGなら → 403 Forbidden
CloudFrontは署名の正当性だけを確認する。ユーザーが誰かは知らないし、知る必要がない。映画館がチケットの偽造防止マークだけ確認するのと同じだ。
設計のポイント
この仕組みの設計で巧みなのは、責務の分離にある:
- アプリケーションが「誰にアクセスさせるか」を判断する(認証・認可)
- CloudFrontは「このURLが本物か」だけ判断する(署名検証)
CloudFrontはユーザー管理を一切しない。だからどんな認証基盤とも組み合わせられる。Cognito、Auth0、自前の認証、なんでもいい。「誰に署名付きURLを渡すか」はアプリ側の責任だ。