0.前提
AIを使って情報の整理・執筆を行なっています。
理解が曖昧だった部分があり、自分自身の理解用に作成したものです。
1. 結論
このテーマは、期限の長さだけでなく、即時失効やアクセス制御をどこまで求めるかで選択肢が変わります。
まず前提として、Lambda / ECS / EC2 / EKS IRSA のような一時クレデンシャル前提では、S3 presigned URL の実効期限は次で決まります。
実効期限 = min(ExpiresIn, 一時クレデンシャルの残存期限)
そのため、「1日(24h)を S3 SigV4 presigned URL で安定運用」は原則不可です。
目安は以下のとおりです。
| 実行基盤 | 実効上限の目安 |
|---|---|
| Lambda | ~1時間 |
| ECS / EC2 | 1〜6時間程度 |
| EKS IRSA | ~12時間 |
要件を分けると、選択肢は次のようになります。
| 要件 | 1時間 | 1日 | 7日 | 30日以上 |
|---|---|---|---|---|
| 即時失効・都度認可が不要 | S3 presigned URL | CloudFront 署名 | CloudFront 署名 | CloudFront 署名 |
| 即時失効・都度認可が必要 | 短命 S3 presigned URL を都度発行 | アプリ認可 + 短命 URL 再発行 | CloudFront 署名 + 再発行 | CloudFront 署名 + 再発行、または アプリ経由配信 |
つまり、長めの期限をただ持たせたいだけなら CloudFront 単独でも成立します。
一方で、失効・監査・ユーザー単位の停止を業務ルールに連動させたいなら、アプリ主導の認可設計が必要です。
2. 先に押さえる前提
2.1 S3 presigned URL の有効期限が決まる仕組み
- S3 presigned URL(SigV4)は、
X-Amz-Expiresにより最大 604800 秒(7日) まで指定できます。 - ただし、一時クレデンシャルで署名した場合は、そのクレデンシャルが失効した時点で URL も失効します。
- そのため、Lambda / ECS / EC2 / IRSA では 7日上限より先にランタイム側の資格情報が切れることが多いです。
- 結果として、1日以上の要件は S3 presigned URL 単体ではなく、設計自体を切り替えるのが基本です。
2.2 S3 presigned URL が即時失効・厳密統制に弱い理由
S3 presigned URL は、発行時点で署名済みの URL(ベアラートークン)として機能するため、個別 URL を後から即時に無効化する仕組みが基本的にありません。
理由は次のとおりです。
-
検証は「署名が正しいか」と「期限内か」が中心
S3 はリクエスト時に SigV4 署名と有効期限を検証しますが、発行済み URL 単位の失効リストを標準では持ちません。 -
URL 発行と後続の細粒度制御が分離している
一度配布された URL は、期限内であれば保持者が利用できます。ユーザー単位で「この URL だけ止める」のは困難です。 -
失効手段が粗い
オブジェクト削除、IAM / バケットポリシー変更、KMS 鍵無効化などの広い対処になりやすく、副作用が大きくなります。 -
監査・再認可を毎回強制しにくい
URL 直接アクセスでは、アプリ側の都度認可ロジックを通らないため、契約停止や権限剥奪の即時反映に弱いです。
つまり、単に期限付きで配布できればよい要件なら大きな問題にならない一方、厳密なアクセス統制が必要な要件では、短命 URL の都度再発行(認可 API 経由) か、CloudFront 署名 + 再発行フロー を使うのが実務上の定石です。
3. ランタイム別の実効上限
| 実行基盤 | 典型的な有効範囲 | 1日 URL の可否 | 補足 |
|---|---|---|---|
| Lambda 実行ロール | ~1時間 | ✕ | Lambda 管理の一時資格情報。長時間 URL には不向き |
| ECS タスクロール | 1〜6時間(実務上) | ✕ | ローテーション前提で 24h 安定運用は不可 |
| EC2 Instance Profile | 最大約6時間 | ✕ | インスタンスプロファイル資格情報は短命 |
| EKS IRSA | ~12時間(設定上限) | ✕ | 24h には届かない |
| IAM ユーザー長期キー | ~7日(SigV4 上限) | ○ | ただし長期キー運用リスクあり |
IRSA とは
IRSA は IAM Roles for Service Accounts の略で、EKS(Kubernetes)上の Pod に IAM 権限を安全に付与する仕組みです。
Kubernetes の ServiceAccount と IAM ロールを紐付け、Pod は AssumeRoleWithWebIdentity で一時クレデンシャルを取得します。
- ノード共通ロールを使わず、Pod 単位で最小権限にできる
- 長期アクセスキー不要で、一時クレデンシャル運用になる
- presigned URL 観点では、URL 実効期限は
min(ExpiresIn, IRSAで取得した資格情報期限)に制約される
つまり IRSA 利用時も、1日以上の URL を S3 presigned URL 単体で安定提供するのは難しく、
必要期間が長い場合は 短命 URL 再発行 または CloudFront 署名 への切替が基本です。
4. 期限別 × 要件別の推奨方式
| 期限 | 即時失効・都度認可が不要な場合 | 即時失効・都度認可が必要な場合 | 補足 |
|---|---|---|---|
| 1時間 | S3 presigned URL | 短命 S3 presigned URL を認可 API 経由で都度発行 |
ExpiresIn=300〜3600 が現実的 |
| 1日 | CloudFront Signed URL / Signed Cookie | アプリ認可 + 短命 URL 再発行(S3 または CloudFront) | 24h は一時クレデンシャル期限に負けるため、S3 presigned URL 単体は不可 |
| 7日 | CloudFront Signed URL / Signed Cookie | CloudFront 署名 + 再発行 | S3 自体の 7日上限より前にランタイム資格情報が切れる |
| 30日以上 | CloudFront Signed URL / Signed Cookie | CloudFront 署名 + 再発行、または アプリ経由配信 | 失効・監査要件が強いほどアプリ主導が安全 |
5. 要件別の実装方針
5.1 即時失効・都度認可が不要な場合
期限切れまで利用できればよく、途中で個別停止しなくてよいなら、選択肢は比較的シンプルです。
- 1時間: Lambda / ECS で S3 presigned URL を直接発行して問題ありません。
- 1日: CloudFront Signed URL / Signed Cookie に切り替えます。
- 7日: CloudFront Signed URL / Signed Cookie が基本です。
- 30日以上: CloudFront Signed URL / Signed Cookie で長期運用できます。
このパターンでは、「期限で切れれば十分」 なので、CloudFront 単独運用でも成立します。
5.1.1 この選択肢でも残るセキュリティリスク
「即時失効が不要」であっても、安全性の考慮が不要になるわけではありません。
単に期限付きで配布できればよい場合でも、主に次のリスクは残ります。
-
URL / Cookie が漏れると、期限内は第三者が利用できる
S3 presigned URL も CloudFront Signed URL / Signed Cookie も、実質的にはベアラートークンです。
メール転送、チャット貼り付け、アクセスログ、ブラウザ履歴、Referer、画面共有などから漏れると、期限が切れるまで利用される可能性があります。 -
期限が長いほど漏洩時の被害時間が長くなる
「即時失効しなくてよい」前提でも、1日・7日・30日と長くするほど、流出後に悪用される時間が伸びます。
特に長期の CloudFront 署名は、運用上は便利でも、漏れたときの回収余地が小さくなります。 -
個別停止ができない、または止めにくい
S3 presigned URL はもちろん、CloudFront の長めの Signed URL / Cookie も、配布後に「この 1 件だけ止める」のが難しいです。
URL 単位の失効管理がないため、途中で止めたい場合は待機、鍵変更、設定変更などの影響範囲が大きい対処になりがちです。 -
S3 側の公開設定ミスで CloudFront を迂回される
CloudFront 前提でも、S3 バケットやオブジェクトが誤って直接参照可能になっていると、CloudFront の署名制御を迂回されます。
CloudFront 利用時は、OAC などで 「S3 は CloudFront からのみ参照可能」 にしておく必要があります。 -
監査・利用者識別は限定的になりやすい
単純な期限付き配布では、利用中の個々のリクエストに対して毎回アプリ認可を通さないため、
「誰の判断で配布したか」「共有された URL を誰が使ったか」を業務的に追いにくいケースがあります。
したがって、即時失効が不要でも「短すぎない最小限の期限」「漏洩しにくい配布経路」「S3 直アクセスの遮断」 は最低限の対策として必要です。
5.2 即時失効・都度認可が必要な場合
契約状態、ユーザー権限、停止フラグ、監査要件などをアクセス継続中にも反映したいなら、URL は短命にし、アプリ側で次のトークンを渡すかどうかを判断する必要があります。
- 1時間: 短命 S3 presigned URL を認可 API 経由で都度発行します。
-
1日:
/downloadAPI のような認可 API 経由にし、60秒〜5分の短命 URL を再発行します。 - 7日: CloudFront 署名 + 再発行 API に寄せます。
- 30日以上: CloudFront 署名 + 再発行、または アプリ経由配信 を選びます。
ここでいう アプリ経由配信 とは、ユーザーに S3 や CloudFront の URL を直接渡さず、
アプリが S3 からファイルを取得して、そのままユーザーへ返す方式 を指します。
このパターンでは、「長く有効な 1 本の URL を渡す」のではなく、「短命にして次を渡さないことで止める」 のが基本になります。
6. CloudFront の使い分け
CloudFront は、長めの期限を持たせる用途にも、短命再発行で制御する用途にも使えます。
そのため、CloudFront 自体が「即時失効前提の仕組み」なのではなく、要件次第で使い方が変わると捉えるのが正確です。
6.1 CloudFront 経由で S3 ダウンロードする基本構造
CloudFront 経由の S3 ダウンロードは、CloudFront を入口にし、S3 を裏側の保管先にする構成です。
ユーザーは S3 ではなく、CloudFront の URL にアクセスします。
配信の流れは次のとおりです。
- S3 に非公開オブジェクトを配置する
- CloudFront Distribution の origin にその S3 バケットを設定する
- S3 は CloudFront からだけ読めるように制限する
- ユーザーは
https://dxxxxx.cloudfront.net/path/file.zipのような CloudFront URL にアクセスする - CloudFront はエッジでキャッシュを確認する
- キャッシュがあればそのまま返し、なければ S3 から取得して返す
- 必要なら CloudFront 側で Signed URL / Signed Cookie を検証して、通ったリクエストだけ配信する
図式化すると次のイメージです。
User
↓ CloudFront URL
CloudFront
├─ キャッシュあり → そのまま返す
└─ キャッシュなし → S3 から取得して返す
↑
private S3
この構成では、CloudFront がキャッシュ兼アクセスゲート、S3 が非公開の保管先になります。
S3 を直接公開せず、配信高速化とアクセス制御を両立できるのが利点です。
なお、S3 を CloudFront 専用の origin にする場合は、通常 OAC(Origin Access Control) を使って 「S3 は CloudFront からのみ参照可能」 にします。
これにより、利用者は S3 直リンクではなく、CloudFront 経由でのみダウンロードする構成にできます。
6.2 パターンA: CloudFront 単独で長めの期限を持たせる
- CloudFront Signed URL / Signed Cookie には、S3 presigned URL のような 7日上限はありません。
- そのため、CloudFront 単独でも 1日 / 7日 / 30日以上 の期限を設定できます。
- CloudFront 側で主にできるのは、次のような技術的な配信制御です。
- 署名が正しいか
- 有効期限内か
- IP 条件に合うか
ただし、このパターンは 「長く見せる」ことには向くが、「今すぐ止める」ことには弱いです。
CloudFront 単独でもアクセス制御はできますが、長期の鍵を渡している間は、その条件を満たす限りアクセスできる性質は残ります。
6.3 パターンB: 即時失効に寄せるため、期限を短くしてアプリ側で再発行する
ユーザー単位の停止や契約失効を即時反映したいなら、CloudFront 側の期限は短くします。
そのうえで、次の署名を渡すかどうかをアプリ側の認可 API で決める構成にします。
重要な点は次のとおりです。
- 再発行 = 新しい署名を新規発行すること
- 古い URL / 古い Cookie は自動では無効にならない
- 古いものは、自分自身の期限が切れるまで使える
- 停止したいときは、次の署名を発行しないことで、短い猶予の後に実質停止させる
つまり、ロジックは 「古い URL を即時失効する」のではなく、「短命にして次を渡さない」 です。
6.4 再発行フローの具体例
- ユーザーが
/download/startを呼ぶ - アプリが契約状態・権限を確認する
- アプリが 5分だけ有効な CloudFront Signed URL を発行して返す
- ユーザーはその URL で 5分以内アクセスできる
- 期限前に
/download/refreshを呼ぶ - アプリが再度認可する
- 問題なければ 新しい 5分 URL を返す
- 停止したい場合は 新しい URL を返さない
- すると、すでに配布済みの古い URL は残り 5分で失効し、その後はアクセスできなくなる
停止の即時性は、いま配っている URL の寿命に依存します。
5分 URL なら最長 5分、1分 URL なら最長 1分で止まります。
6.5 CloudFront とアプリの役割分担
| 役割 | 担当 | 内容 |
|---|---|---|
| 配信ゲート | CloudFront | 署名・期限・IP 条件で配信可否を判定 |
| 業務ルール判定 | アプリ | 契約状態、ユーザー権限、停止フラグ、テナント条件で再発行可否を判定 |
整理すると、次の住み分けになります。
- CloudFront 単独: 長期期限は設定できる
- 即時失効したい: 期限を短くして、アプリ側で再発行制御する
CloudFront にアクセス制御機能がないわけではなく、CloudFront 単独で得意なのは「期限付き配信」までです。
業務状態に応じた細かい停止制御はアプリで担保する、というのが実務上の整理です。
6.6 短命再発行パターンで使える CloudFront 機能
-
Signed URL / Signed Cookie
CloudFront 配信そのものに期限を付けられます。 -
Custom Policy
期限だけでなく IP 条件も付けられます。 -
Key Group
公開鍵のローテーションをしやすくなります。 -
Signed Cookie のパス単位制御
例:/customer-a/*のように、まとまった配布単位を扱いやすいです。
7. 注意点
-
ExpiresInを長くしても効かないケースが多い
根本は資格情報期限です。まず実行基盤のクレデンシャル寿命を確認します。 -
URL はベアラートークン
ログ・履歴・共有で漏れれば誰でもアクセスできます。短命化と最小配布が前提です。 -
失効要件があるなら再発行方式を前提にする
発行済み URL を後から止めるのは難しいため、認可 API 経由に寄せます。 -
大容量ダウンロードは再開失敗を考慮する
期限切れ後の再開で失敗しうるため、再発行導線を用意します。
8. 最終推奨
- まず「長い期限が欲しいだけなのか」「即時失効・都度認可も必要なのか」を分けて判断する
- Lambda / ECS 中心では、S3 presigned URL は基本的に 1時間以内ユース向き
- 1日以上で失効要件が弱いなら CloudFront 署名を第一候補にする
- 1日以上で失効・監査要件が強いなら、CloudFront または S3 の短命 URL をアプリ認可で再発行する