- 旧サイトから新サイトにリダイレクトする
- index.html なしでドキュメントを表示して URL の正規化もする
- IP 制限をかける
- Basic 認証をかける
- オリジンの 403 Forbidden を 404 Not Found に書き換える
旧サイトから新サイトにリダイレクトする
EC2 が稼働しているなら Apache やら Nginx でリダイレクトしてもいいが、移転やサービス終了に伴い Web サーバを解体することになった場合に有用。
毎月 200 万リクエストまでは無料枠に収まるし、それを超えても 1 リクエストあたり 0.0000001 USD しかかからない。
最低でも CloudFront にデフォルトオリジンが必要になるため空の S3 バケットを作成しておく必要がある。バケットはオリジンとして指定できればいいだけなのでパブリックにしたり OAI(Origin Access Identity)を設定する必要も無い。
なお、CloudFront を構築したあとにバケットを削除すればバケットすら不要になる。
function handler(event) { return { statusCode: 301, statusDescription: 'Moved Permanently', headers: { location: { value: 'https://example.com', }, }, }; }
ビューワーを新しい URL にリダイレクトさせる - Amazon CloudFront
index.html なしでドキュメントを表示して URL の正規化もする
CloudFront と S3 で静的コンテンツを配信している場合、CloudFront のデフォルトルートオブジェクトを指定すればルートディレクトリだけは index.html
無しでも表示できるがサブディレクトリは index.html
等が必要になる。
index.html
無しでオリジンにリクエストする例については下記にサンプルが掲載されている。
index.html を追加してファイル名を含まない URL をリクエストする - Amazon CloudFront
このサンプルを使うと index.html
あり・なしどちらでもアクセスができるようになるのだけど恐らく検索エンジンに両方登録されてしまうので SEO 対策として正規化して index.html
なしに統一する。
event.request
に scheme は無いのでこの部分はハードコーディングになりそう?
function handler(event) { var request = event.request; var uri = request.uri; // uri が /index.html で終了している場合は /index.html 無しに 301 リダイレクト if (uri.endsWith('/index.html')) { return { statusCode: 301, statusDescription: 'Moved Permanently', location: { value: 'https://' + request.headers.host.value + uri.replace(/\/index\.html$/, ''), }, }; } // uri が / で終了している場合は index.html を付与してオリジンにリクエストする if (uri.endsWith('/')) { request.uri += 'index.html'; // uri が . を含まない(≒拡張子が存在しない)場合は /index.html を付与してオリジンにリクエストする // 上の 301 リダイレクトしたものはここで処理される } else if (!uri.includes('.')) { request.uri += '/index.html'; } return request; }
IP 制限をかける
CloudFront で 403 のカスタムエラーページを設定している場合、WAF で IP 制限を設定するとカスタムエラーレスポンスのページを返却してしまう。CloudFront Functions であればステータスコードだけを返却できる。CloudFront Functions では body はいじれないらしく、その場合は Lambda@Edge を使わなければならない模様。
CloudFront Functions で HTTP レスポンスを生成する場合、レスポンス本文を含めることはできません。生成された HTTP 応答にレスポンス本文を含める必要がある場合は、Lambda@Edge を使います 。
event
の構造は下記に記載がある。
CloudFront Functions のイベント構造 - Amazon CloudFront
function handler(event) { var allowedIps = [ '1.2.3.4', '5.6.7.8', ]; if (!allowedIps.includes(event.viewer.ip)) { return { statusCode: 403, statusDescription: 'Forbidden', }; } return event.request; }
Basic 認証をかける
クラスメソッドさんの記事で紹介されていたもの。
WAF でも同じようなことが出来るのだけど authorization
ヘッダーが無いか Basic 認証の Base64 文字列と一致しなければステータス 401 と www-authenticate: Basic
ヘッダーを返却して Basic 認証を要求する。
反応が早い分総当り攻撃で突破されてしまいそうな気がしないでもない。
function handler(event) { var authString = 'Basic dXNlcjpwYXNzd29yZA=='; var request = event.request; if ( typeof request.headers.authorization === 'undefined' || request.headers.authorization.value !== authString ) { return { statusCode: 401, statusDescription: 'Unauthorized', headers: { 'www-authenticate': { value: 'Basic', }, }, }; } return request; }
オリジンの 403 Forbidden を 404 Not Found に書き換える
中身無しのシンプルな書き換えが出来ると思ったがビューワーレスポンスに関連付けされている場合はレスポンスコードを書き換えることは出来ないらしい。(関数のテストでは出来る)
関数がビューワーレスポンスイベントタイプに関連付けられている場合 、関数コードは受信した statusCode を変更できません。関数がビューワーリクエストイベントタイプに関連付けられ、HTTP レスポンスを生成する場合は、関数コードで statusCode を設定できます。
function handler(event) { var response = event.response; if (response.statusCode == 403) { return { statusCode: 404, statusDescription: 'Not Found', }; } return response; }
CloudFront Functions は ES 5.1 準拠で一部 ES 6.x 以降の機能や非標準機能も含まれている。