この記事は フラー株式会社 Advent Calendar 2022
11日目の記事です。
10日目は @nnsnodnb
さんで Firebase App Distribution で配信するための CircleCI Orb を自作した
でした。
はじめに
早いもので前回のブログから1年経ってしまいました。(去年も同じこと言ってる)
毎年のことながらブログを書く前にhugoのアップデートとCIのアップデートにばかり時間を使ってしまいました。
来年はこれだけで記事がかけるかもしれない
さて、今回もとある案件でのお話です。
今回は静的コンテンツを特定の認証されたユーザーのみに配信するという要件がありました。(よくありますね!)
かんたんにPrivateなS3バケットのコンテンツを安全に配信できる方法ないかな〜とぼんやり考えていた時にあることを思い出しました。それは2021年のISUCON予選の振り返り会をしている時に、@sora_hさんが「実は認証のみアプリケーションで行い画像の配信はnginxで行えたんですよ〜」という話をしていて「そんなことできるのか!すげぇ〜」と感動したことがあったのです。
当時はDBにバイナリーで格納されている画像ファイルをエクスポートしてnginxで配布することでDBサーバーへの負荷軽減につながるという話だったのですが、まさかこんな形で業務で使うことになるとはISUCON様様です。
今回はマネーフォワードさんのテックブログS3のファイルをX-Accel-Redirectで配信する を参考にgoで実装してみます
X-Accel-Redirect とは
以下本家のドキュメントより引用
X-accel allows for internal redirection to a location determined by a header returned from a backend.
This allows you to handle authentication, logging or whatever else you please in your backend and then have NGINX handle serving the contents from redirected location to the end user, thus freeing up the backend to handle other requests. This feature is commonly known as X-Sendfile.
<翻訳>
X-accelでは、バックエンドから返されるヘッダによって決定される場所への内部リダイレクトが可能です。
これにより、バックエンドで認証、ログ、その他何でも処理し、NGINXにリダイレクトされた場所からエンドユーザーへのコンテンツを提供させ、 バックエンドを他のリクエストの処理に解放させることができるようになります。この機能は一般的にX-Sendfileとして知られています。
ということでX-Accelヘッダーを使うことで別の場所に内部的にリダイレクトさせることができるようです
今回やりたいこと
- ユーザーリクエストの認証をアプリケーション側で実施
- S3に格納されているファイルの配信はnginxで行う
nginxからS3へのアクセスは署名付きURLでも可能ですが、上記記事でも触れられているようにURLが外部に漏洩した場合誰でも見れる状態になってしまう為、記事と同じくAWS 署名バージョン4 で進めます。
自分の中で整理する為に改めてシーケンスを書きました
やるべきことは以下の通り
- S3のバケット情報からAWS 署名v4 の認証情報を生成する ⑤
- 生成した認証情報をアプリケーションのレスポンスヘッダーにセットしてnginxに渡す ⑦
- X-Accel-Redirectで指定されたパスの設定 ⑧
1. AWS 署名v4 の認証情報を生成する
はじめに⑤のAWS 署名バージョン4で署名する部分です
gits/main.go
AWS 署名v4の認証情報取得サンプル
github.com
1.1 signerを初期化
実行するロールにS3の参照権限が必要です
|
|
1.2 URLへアクセスする為の認証情報を作成
シーケンス図⑤のnginxがS3へリクエストする為に必要な認証情報の作成をします
signer.SignHTTP
に渡したreqに認証用のヘッダーがセットされます
|
|
これで認証情報の生成が完了しました。
このサンプルではcurlコマンドを利用して動作確認していますが実際はレスポンスヘッダーに各値を追加する必要があります。
2. 生成した認証情報をレスポンスヘッダーにセットする
例:http.Header
を受け取りレスポンスヘッダーにセットする
3. X-Accel-Redirectで指定されたパスの設定
アプリケーションでレスポンスヘッダーに設定した値をproxy_set_header
でセットし直します
これでS3のファイルをX-Accel-Redirectを用いて取得することができるよになりました。
まとめ
S3のURLを元にAWS 署名v4で認証情報を生成し、nginxのX-Accel−Redirectを使うことで認証情報を外部に漏洩させずにファイルを取得できるようになりました。
S3のファイルをX-Accel-Redirectで転送するためには以下の設定が必要です
- nginxからS3へのファイル参照をするためにアプリケーション側でAWS 署名v4を利用し認証情報を取得する
- レスポンスヘッダーに
X-Accel-Redirect
と取得した認証情報をセットする - X-Accel-Redirect先の設定で
proxy_set_header
を利用してヘッダーをセットする
余談(ハマったポイント)
実装をする中でハマったことがありました。
手元のターミナルでは正しく取得できるが サーバーにデプロイしたらS3から403が返却される事象に悩まされました。
原因は手元の実行ロールは管理者権限で動いており、S3ファイルを参照できる権限があったがサーバーには参照する権限がなかったため権限エラーになりました。
AWS 署名v4の認証情報の確認は接続した時に発行したロールの権限に依存します。
したがってサーバー側にアタッチメントしてるロールにS3の参照権限を事前に設定しておく必要があります。
明日はフラー株式会社 Advent Calendar 2022 12日目 @nnsnodnb さんで を食べる です お楽しみに〜