S3のリダイレクト機能を改めて整理してみた
はじめに
清水です。AWSのオブジェクトストレージサービスであるAmazon S3、静的ウェブサイトホスティング機能を有効にすることでリダイレクト機能も使用することができます。このリダイレクト機能ですが、個人的なイメージとしてZone Apexなドメインexample.com
をwww付きのドメインwww.example.com
にリダイレクトする(つまりドメインAから別のドメインBにリダイレクトする)のに便利だよね、ぐらいの大まかな印象でおりました。最近はALBのリダイレクト機能を使用することも多かったのですが(固定IPアドレスでフルマネージドなリダイレクト環境をAWSで構成する | DevelopersIO)、その際の設定項目と比較してS3のリダイレクト機能ではこれはできたっけ?と思うこともあり、今回改めてS3のリダイレクト機能を整理してみようと思います。
S3のリダイレクト機能
まず前提として、S3のリダイレクト機能は静的ウェブサイトホスティング機能のオプションとして利用可能です。この静的ウェブサイトホスティング機能を有効化した場合の特徴や、HTTPS対応などを本節ではまとめます。また本エントリではS3のリダイレクト機能について、ユーザガイドの項目をもとに以下3つに分類します。((オプション) ウェブページリダイレクトの設定 - Amazon Simple Storage Service)これらそれぞれの詳細について次節以降でそれぞれまとめています。
- S3ウェブサイトエンドポイントへのリダイレクト設定
- S3バケット(静的ウェブサイトホスティングのエンドポイント)全体にリダイレクト設定を行います。S3マネジメントコンソールでは Redirect request とも表示されます。ユーザガイドでは「バケットのウェブサイトエンドポイントに対するリクエストを別のバケットまたはドメインにリダイレクトする」に該当します。
- リダイレクトルールを使った設定
- 静的ウェブサイトホスティング設定中のS3バケットに対して、リダイレクトルールを使って多種多様なリダイレクトを設定することができます。ルールにマッチしないオブジェクトへのリクエストに対しては、通常の静的ウェブサイトホスティングとしてレスポンスが返ります。S3マネジメントコンソール上では Bucket Hosting として表示されます。ユーザガイドでは「高度な条件付きリダイレクトを使用するようにリダイレクトルールを設定する」に該当します。
- オブジェクト単位でのリダイレクト設定
- 個々のS3オブジェクトごとにリダイレクトの設定を行います。設定を行っていないオブジェクトは通常の静的ウェブサイトホスティングとして利用可能です。こちらもS3マネジメントコンソール上では Bucket Hosting として表示されます。ユーザガイドでは「オブジェクトのリクエストをリダイレクトする」に該当します。
リダイレクト機能は静的ウェブサイトホスティング機能のオプション
前提として、S3のリダイレクト機能は静的ウェブサイトホスティング機能のオプションとして利用可能です。そのため静的ウェブサイトホスティング機能の特徴を把握しておく必要があります。メリット面なども多くありますが(Amazon S3 + Amazon CloudFrontでWebサイトを構築する際にS3静的Webサイトホスティングを採用する理由 | DevelopersIO)、注意点としては、静的ウェブサイトホスティングのエンドポイントがHTTPでのみしか提供されていないこと、またCloudFront連携した場合にもOAIが利用できないため静的ウェブサイトホスティングのエンドポイントへのアクセスが完全には防げないこと、などが挙げられます。後者はS3バケットの名称をわかりにくものにする、などの対応は可能ですが、アクセスできる状態にあることが問題になる場合などは注意です。もしCloudFrontからリダイレクト環境となるオリジンへの通信もHTTPSとしたい、といった場合にはALBのリダイレクト機能を使う、などの必要があるかと思います。Lambda@Edgeでリダイレクトさせる、ということもできそうですね。(Lambda@Edgeを使ってリファラによってリダイレクトさせる | DevelopersIO)
HTTPS利用の場合はCloudFrontと連携
リダイレクト機能を使うための静的ウェブサイトホスティング機能の特徴として、エンドポイントがHTTPでのみしか提供されていないことを挙げました。(個人的に少し勘違いしていたのですが、独自ドメインのHTTPSがサポートされていない、ではなく、静的ウェブサイトホスティングのエンドポイントのHTTPS自体がサポートされていません。)そのため、HTTPS利用の場合はCloudFrontと連携します。S3の静的ウェブサイトホスティング利用の場合の鉄板パターンですね。独自ドメインも利用可能です。本エントリではCloudFrontとの連携部分や割愛し、リダイレクトの挙動確認もS3の静的ウェブサイトホスティングのエンドポイントを使って行います。実際のCloudFrontとの連携については以下などを参照ください。
- CloudFront を使用して Amazon S3 バケットに対する HTTPS リクエストを処理する
- CloudFront – S3 オリジンの構成でリダイレクトさせる方法を教えてください | DevelopersIO
なお、後述しますがリダイレクトの際にパス情報のほかクエリ文字列の情報もLocationヘッダに付与することが可能です。この場合、CloudFrontからみてオリジンとなるS3にクエリ文字列を転送する必要がある点に注意しましょう。
本エントリで利用するS3バケット共通の設定
以下、本エントリの検証にあたっては、S3バケットのブロックパブリックアクセス設定を無効にし、以下形式のバケットポリシーを設定しています。(バケット配下の任意のオブジェクトが公開される設定となります。)またS3バケットはすべて東京リージョンに作成しました。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadGetObject", "Effect": "Allow", "Principal": "*", "Action": [ "s3:GetObject" ], "Resource": [ "arn:aws:s3:::Bucket-Name/*" ] } ] }
S3ウェブサイトエンドポイントへのリダイレクト設定
まずはS3ウェブサイトエンドポイントへのリダイレクト設定を確認します。冒頭に述べたような、Zone Apexドメインexample.com
へのアクセスをwww.example.com
にリダイレクトする、というシンプルなリダイレクトが実現可能です。S3のリダイレクト機能でも最もオーソドックスなものではないでしょうか。
後述しますが、リダイレクトの際にはリクエスト時のパスやクエリ文字列もLocationヘッダに含まれます。例えばこれまでexample.com
で運用していたページをなんらかの事情でwww.example.com
に移管したとします。リダイレクト設定を行い新しいドメインにユーザを誘導したいのですが、可能であればパスやクエリ文字も含めてリダイレクトしたい、という場合に利用できます。
他2つのリダイレクト設定とは異なり、静的ウェブサイトホスティングの際に Redirect request という項目で設定するので、本エントリでもこれにならいRedirect requestと記してみたいと思います。
Redirect requestを設定してみる
実際にS3バケットに対して、このウェブサイトエンドポイントへのリダイレクト設定(Redirect request)行ってみます。S3バケットの中身は空(オブジェクトが存在しない)状態です。
S3マネジメントコンソールで該当のS3バケットを選択、Propertiesの項目を選択します。
一番下まで画面をスクロールすると、Static website hostingの項目があります。デフォルトではDisabled
になっているので[Edit]ボタンで設定していきます。
Static website hostingでEnable
を選択、Hosting typeでRedirect request for an object
を選択します。新たに現れるHost nameの項目にリダイレクト先となるドメイン名を指定します。今回はwww.example.com
としました。Protocolの項目ではhttps
を選択しておきます。
設定後の画面です。以下のようにウェブサイトホスティング用のエンドポイントが表示されます。ドメイン名はバケット名.s3-website-ap-northeast-1.amazonaws.com
という形式となります。(なおこの形式については、リージョンごとでs3-website-Region
となるかs3-website.Region
となるかの違いがあるようです。詳細はユーザガイドや実際のマネジメントコンソールなどの表示を確認してください。)
実際にリダイレクトのレスポンスを確認してみます。
% curl -I http://s3-redirect-1-XXXXXX.s3-website-ap-northeast-1.amazonaws.com HTTP/1.1 301 Moved Permanently x-amz-id-2: xRr/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x-amz-request-id: 71HYxxxxxxxxxxxx Date: Sat, 31 Jul 2021 04:04:25 GMT Location: https://www.example.com/ Server: AmazonS3 Content-Length: 0
ステータスコードとして301 Moved Permanently
がレスポンスとして返り、別ドメインにリダイレクトされるという挙動です。Locationヘッダにはリダイレクト先となる、指定したドメインが入ります。また先ほどProtocolでhttps
を指定したとおりhttpsプロトコルとなりリダイレクト先はhttps://www.example.com/
となります。
なお、Protocolでhttpを選べばリダイレクト先(Locationヘッダの値)はhttp://www.example.com/
となりました。none
を選択したときの挙動も同様でした。また、上記curlコマンドの例ではレスポンスヘッダのみ示していますが、レスポンスボディは特にありません。Content-Lengthヘッダの値も0
となっていますね。
パスとクエリ文字列の扱い
続いてパスとクエリ文字列の扱いについて確認します。結論としてはこのRedirect requestのリダイレクト設定では、リクエスト時のパスとクエリ文字列がレスポンスのLocationヘッダに追加されて返ってきます。
% curl -I "http://s3-redirect-1-XXXXXX.s3-website-ap-northeast-1.amazonaws.com/path/to/file.html?query=string&key=value" HTTP/1.1 301 Moved Permanently x-amz-id-2: ZiPLxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x-amz-request-id: 9562xxxxxxxxxxxx Date: Sat, 31 Jul 2021 04:23:43 GMT Location: https://www.example.com/path/to/file.html?query=string&key=value Server: AmazonS3 Content-Length: 0
実は個人的に、「あれ?どうだっけ?」と思っていたのはこの点でした。ALBのリダイレクト機能の以下の設定状況と同様の挙動かと思います。
リダイレクト先にパスを追加できる
確認しながら気になったこととして、リダイレクト先のHost nameにパスは追加できるのか?という点があります。以下のような設定ですね。
このまま[Save changes]で設定できたので、挙動を確認してみます。以下のようにパスを追加したかたちでLocationヘッダが返ってきました。
% curl -I http://s3-redirect-1-XXXXXX.s3-website-ap-northeast-1.amazonaws.com HTTP/1.1 301 Moved Permanently x-amz-id-2: Wdx5xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x-amz-request-id: S07Qxxxxxxxxxxxx Date: Sat, 31 Jul 2021 04:25:36 GMT Location: https://www.example.com/path/ Server: AmazonS3 Content-Length: 0
なお、リクエストURLにパスを追加すると、さらにパスが加わる具合です。
% curl -I http://s3-redirect-1-XXXXXX.s3-website-ap-northeast-1.amazonaws.com/path/to/file.html HTTP/1.1 301 Moved Permanently x-amz-id-2: RSxwxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x-amz-request-id: HJA5xxxxxxxxxxxx Date: Sat, 31 Jul 2021 04:27:26 GMT Location: https://www.example.com/path/path/to/file.html Server: AmazonS3 Content-Length: 0
S3ウェブサイトエンドポイントへのリダイレクト設定はブロックパブリックアクセスが有効でも機能する
Edit static website hostingの項目を設定中に気がついたのですが、Hosting typeがHost a static website
(Bucket Hosting)の場合だと、「パブリックアクセス可にする必要がある」とインフォメーションが現れますが、Redirect requests for an object
(Redirect request)の場合はインフォメーションが現れません。
これはもしや、S3でパブリックアクセス不可、ブロックパブリックアクセスを有効にした状態でも、静的ウェブサイトホスティングを有効にしていればエンドポイントのリダイレクト設定は機能するのかな、と思ったらその通りでした。(具体的にはブロックパブリックアクセスを有効、バケットポリシーが空の状態で確認しています。あくまで個々のオブジェクトにアクセスしているわけではなく、静的ウェブサイトホスティングのエンドポイントで処理している、ということかと推測します。
リダイレクトルールを使った設定
続いてリダイレクトルールを使った設定です。先ほどのS3ウェブサイトエンドポイントへのリダイレクト設定ではバケット全体で一つのリダイレクト設定を行う具合でしたが、リダイレクトルールを使うと条件に応じたきめ細やかなリダイレクトの設定が可能です。
例えばリダイレクト先のドメインではパスやクエリ文字列の扱いが異なるため、example.com
ドメインへのアクセスを一括して(どんなパス、クエリ文字列がついていたとしても)https://www.example.com/
にリダイレクトさせたい、という設定が行えます。またステータスコードを301
ではなく302
としたい、といった変更も可能です。これらは先ほどのS3ウェブサイトエンドポイントへのリダイレクト設定では行えなかったことですね。そのほかにも、特定のパスを同じドメイン内の別のパスにリダイレクトさせたり、404エラーが発生した場合にリダイレクトさせる、といったことが可能です。より詳細な設定項目についてはユーザガイドを参照ください。(「高度な条件付きリダイレクトを使用するようにリダイレクトルールを設定する」 (オプション) ウェブページリダイレクトの設定 - Amazon Simple Storage Service)
リダイレクトルールは多様なリダイレクト設定が行えるため、先ほど確認したS3ウェブサイトエンドポイントへのリダイレクトと同等のリダイレクト設定も実現可能です。(パスやクエリ文字列情報がリダイレクト先に引き継がれるパターン)後述するオブジェクト単位でのリダイレクト設定と同様なことも実現可能かと思います。多様な設定が行える分、リダイレクトルールをきちんと理解して記述する必要があります。なおこのリダイレクトルールの記述方法ですが、従来はXML記法でした。最新のユーザガイドを確認するとS3マネジメントコンソールからの設定ではJSON記法で記述する方式になったようです。(きちんと確認はしていませんが、おそらくCORS指定の記法がJSONに変わったタイミングと同じかなと推測しています。AWSマネジメントコンソールからのAmazon S3のCORS設定方法がJSON記法になっていました | DevelopersIO)
それでは実際にS3バケットに設定してみます。設定箇所は先ほどと同様の場所です。Hosting typeで今回はHost a static website
を選択します。(今回、試してみる構成とは異なりますが、特定のパスのみリダイレクトを行い他のパスでは通常の静的ウェブサイトホスティングを行う、という構成が可能です。そのため、バケット全体がリダイレクト設定となるRedirect requestの設定ではなく、あくまで静的ウェブサイトホスティングの設定、Bucket Hostingなのかなと思います。)
Index documentとError documentを適切に入力して(Index documentは指定必須です)、Redirection rulesを入力します。
Redirection rulesは以下の内容を入力しました。(リダイレクト先はnew.example.com
としています。)
[ { "Redirect": { "HostName": "new.example.com", "HttpRedirectCode": "301", "Protocol": "https", "ReplaceKeyWith": "" } } ]
実際にcurlコマンドで確認してみます。まずはパスやクエリがないパターンです。意図したとおり、https://new.example.com/
への301リダイレクトとなっています。
% curl -I http://s3-redirect-2-XXXXXX.s3-website-ap-northeast-1.amazonaws.com HTTP/1.1 301 Moved Permanently x-amz-id-2: 9WCnxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x-amz-request-id: 1VVExxxxxxxxxxxx Date: Sat, 31 Jul 2021 04:50:09 GMT Location: https://new.example.com/ Server: AmazonS3 Content-Length: 0
続いてパスを追加してみます。パスを省いたかたちのLocationヘッダが返ります。
% curl -I http://s3-redirect-2-XXXXXX.s3-website-ap-northeast-1.amazonaws.com/path/to/file.html HTTP/1.1 301 Moved Permanently x-amz-id-2: j+G+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x-amz-request-id: HDDJxxxxxxxxxxxx Date: Sat, 31 Jul 2021 04:52:44 GMT Location: https://new.example.com/ Server: AmazonS3 Content-Length: 0
パスに加えてクエリ文字列も追加してみます。こちらも省いたかたちのLocationヘッダが返ってきましたね。
% curl -I "http://s3-redirect-2-XXXXXX.s3-website-ap-northeast-1.amazonaws.com/path/to/file.html?query=string&key=value" HTTP/1.1 301 Moved Permanently x-amz-id-2: zPo1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x-amz-request-id: F419xxxxxxxxxxxx Date: Sat, 31 Jul 2021 04:53:28 GMT Location: https://new.example.com/ Server: AmazonS3 Content-Length: 0
繰り返しになりますが、リダイレクトルールではこの他にもいろいろなリダイレクト設定が可能です。以下エントリなどもあわせてご参照ください。
オブジェクト単位でのリダイレクト設定
S3の静的ウェブサイトホスティングではオブジェクト単位でリダイレクト設定を行うことも可能です。例えばexample.com
でS3の静的ウェブサイトホスティングを使ったサイトを運用していたとします。example.com/specialpage.html
というページがこれまでもありましたが、このページを新しくspecialpage.example.com
という別のドメインで運用をはじめるためリダイレクトしたい、という場合に使用できます。その他、別ドメインでなく同じS3バケット内の別オブジェクトにリダイレクトする、といケースにも利用可能です。(こちらの例はユーザガイドを参照ください。)
実際に上記の例の挙動を設定して確認してみます。他の手順と同様に静的ウェブサイトホスティングを有効にしたS3バケットを準備します。Redirect requestの設定はせずBucket Hostingの設定とし、またリダイレクトルールは設定していない状態です。このS3バケットに、specialpage.htmlをアップロードしておきます。
% curl -i http://s3-redirect-3-XXXXXX.s3-website-ap-northeast-1.amazonaws.com/specialpage.html HTTP/1.1 200 OK x-amz-id-2: BsACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x-amz-request-id: 445Xxxxxxxxxxxxx Date: Sat, 31 Jul 2021 05:05:57 GMT Last-Modified: Sat, 31 Jul 2021 05:05:15 GMT ETag: "7a075b3dac882740335ebbff1d01aab5" Content-Type: text/html Server: AmazonS3 Content-Length: 111 <html> <head> <title>special page</title> </head> <body> This is special page. </body> </html>
マネジメントコンソールからこのオブジェクトspecialpage.html
のPropertiesの項目を確認します。
ページ最下部のほうまでスクロールするとMetadataという項目があるので、[Edit]ボタンで進めます。
Metadataの項目で[Add metadata]からデータを1つ追加します。TypeではSystem defined
を選択します。Keyではx-amz-website-redirect-location
を選択し、Valueにリダイレクト先のURLを入力します。今回はhttps://specialpage.example.com/
と入力しました。
以下が設定後の状態です。
設定後、このオブジェクトを参照してみます。以下のように301 Moved Permanently
のリダイレクト用レスポンスが返りました。Locationヘッダは先ほど設定したhttps://specialpage.example.com/
となっています。Content-Lengthヘッダも0
となり、これまであったコンテンツを返さず、リダイレクト用の情報のみを返していることがわかります。
% curl -i http://s3-redirect-3-XXXXXX.s3-website-ap-northeast-1.amazonaws.com/specialpage.html HTTP/1.1 301 Moved Permanently x-amz-id-2: csvCxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x-amz-request-id: B8YExxxxxxxxxxxx Date: Sat, 31 Jul 2021 05:18:30 GMT Location: https://specialpage.example.com/ Server: AmazonS3 Content-Length: 0
リダイレクトルールを使用しても同様の設定は実現できるかと思いますが、リダイレクトさせるパスが1つと決まっており、リダイレクト先なども上記要件にマッチするのであれば、リダイレクトルールよりもシンプルに設定できるのかなと思います。ただし、リダイレクトの設定は各オブジェクトのメタデータを参照して確認する必要がある点には注意しましょう。(設定するオブジェクトの数が多くなった場合、きちんと管理していないと確認などで苦労しそうな印象です。)
なお、このオブジェクトに(静的ウェブサイトのエンドポイントではなく)REST APIエンドポイントでアクセスすると上記設定を行った状態でオブジェクトの内容の参照が可能でした。静的ウェブサイトのエンドポイントにアクセスした場合、該当オブジェクトにx-amz-website-redirect-locatio
のメタデータがあるか確認、あった場合はリダイレクトのレスポンスを返す、という挙動でしょうか。この点が気になる場合は0バイトのオブジェクトとしてspecialpage.htmlをアップロードし直し、そちらにMetadataを設定するようにしましょう。
% curl -i http://s3-redirect-3-XXXXXX.s3.ap-northeast-1.amazonaws.com/specialpage.html HTTP/1.1 200 OK x-amz-id-2: sa9Sxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x-amz-request-id: A016xxxxxxxxxxxx Date: Sat, 31 Jul 2021 05:27:03 GMT Last-Modified: Sat, 31 Jul 2021 05:17:28 GMT ETag: "7a075b3dac882740335ebbff1d01aab5" x-amz-website-redirect-location: https://specialpage.example.com/ Accept-Ranges: bytes Content-Type: text/html Server: AmazonS3 Content-Length: 111 <html> <head> <title>special page</title> </head> <body> This is special page. </body> </html>
まとめ
Amazon S3のリダイレクト機能について、ウェブサイトエンドポイント自体にリダイレクト設定を行う方法、ウェブサイトホスティングをしながらリダイレクトルールを使って設定する方法、オブジェクト自体にリダイレクトを設定する方法、3つをまとめてみました。もともとS3でウェブサイトホスティングをしていない状況で、冒頭で述べたようなZone Apexなドメインexample.com
をwww付きのドメインwww.example.com
にリダイレクトする、といった別ドメインにリダイレクトするようなシンプルなパターンでは、まずS3ウェブサイトエンドポイントへのリダイレクト設定を検討しましょう。もしパスやクエリ文字列を省いたかたちでリダイレクトさせたい、といった場合にはリダイレクトルールを使うことを検討します。またS3でウェブサイトホスティングを行っていて、特定のオブジェクトでリダイレクトさせたい場合は、まずオブジェクト単位でのリダイレクト設定を検討するとシンプルかと思います。その他より複雑な条件でのリダイレクトにはリダイレクトルールを使用、といった使い分けになります。個人的に、今回S3のリダイレクト機能をまとめるにあたって大まかな印象がだいぶクリアになりました。と同時に、S3のリダイレクト機能が多機能であることと、また単に「リダイレクト」といっても様々な条件があるよなぁと考えさせられたしだいです。