CloudFront Functionsのみで指定IP以外はメンテナンス画面(html)を表示する方法。検索するとS3と組み合わせる例はたくさん出てくるのですが、この方法は出てこなかったので残しておきます。
S3を組み合わせると困る点
CloudFront -> S3(オリジン)の構成で、S3にメンテ画面用のHTMLを置くとhttps://example.com/mainte.html
ではメンテ画面を出せても、他のURLにアクセスされると404になってしまい、メンテ画面を出せない。
このため、CloudFrontの404ページをmainte.htmlに変更し、ステータスコードも503を返す設定(ディストリビューション→エラーページ→カスタムエラーレスポンス)が必要となる→設定も戻すのも面倒。
CloudFront Functionsでbodyを返却
下記の方法だとビューワーリクエスト(ビヘイビア→関数の関連付け)の関数をメンテ用の関数に変更するだけでメンテナンス画面が出せる。どうやらかつてはbodyを返却することができなかったぽい?のだが、現在は可能。
CloudFront Functions イベント構造
https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/functions-event-structure.html
注意点としては、CloudFront Functionsのファイル容量は10KB以内でないと駄目なので、あまりリッチな画面は作れないこと。試してはいないのですが、cssや画像などは200で返っても問題ないので、そのあたりはS3など静的配信可能なものに入れて、それをhtmlで参照すると良さそう。
コード
cloudfront-js-2.0で実行させる
function handler(event) {
const request = event.request;
// メンテ画面を出さずに通すIPリスト
const sourceIP = event.viewer.ip;
const ALLOWED_IPS = [
"xx.xx.xx.xx",
"yy.yy.yy.yy",
];
// メンテナンス用HTML
const html = `
<!DOCTYPE html>
<html>
<head>
<title>Site under maintenance</title>
</head>
<body>
<h1>Site under maintenance</h1>
<p>We are currently performing maintenance on our website. Please check back later.</p>
</body>
</html>
`;
const base64EncodedBody = Buffer.from(html, "utf8").toString("base64");
// 指定IP以外はメンテ画面を503で出す
if (!ALLOWED_IPS.includes(sourceIP)) {
const response = {
statusCode: 503,
statusDescription: "Service Temporarily Unavailable",
headers: {
"content-type": {
value: "text/html",
},
"cache-control": {
value: "no-store, no-cache, must-revalidate, max-age=0",
},
pragma: {
value: "no-cache",
},
expires: {
value: "0",
},
},
body: {
data: base64EncodedBody,
encoding: "base64",
},
};
return response;
}
return request;
}
今までmod_rewriteでゴニョゴニョやっていたことを考えると、ずいぶん分かりやすくできることも増えたので、このサービス好き。