はじめに
Webサービスの運用において、リリース作業や障害対応などの理由で、特定のユーザーのみを許可して、他のユーザーにはメンテナンスページを表示したいというケースはよくあります。
このような場合、メンテナンスぺージを表示したいタイミングで、許可されていないユーザーをブロックして、メンテナンス用のページを表示することでメンテナンスページへの切り替えを実現します。
本記事ではCloudFormationを使用して、S3 + CloudFront + WAFによるメンテナンスページへの切り替え方法を紹介します。
構成
本記事で作成する構成は下記となります。

各サービスの役割
- WAF
メンテナンス時のみ CloudFront にアタッチして IP 制限を有効化します。 - CloudFront
通常時は、すべてのユーザーにindex.html(通常ページ)を返します。
メンテナンス時は、WAFにより許可していないユーザーにはメンテナンスページを表示するようにアクセス制御を行います。
メンテナンス時は、許可したユーザの場合、WAFを通過し、index.html(通常ページ)を返します。
一方で、許可されていないユーザーの場合、WAFによりブロックされ、403エラーをCloudFrontが検知して、カスタムエラーレスポンスによりmaintenance.html(メンテナンスページ)を返します。 - S3バケット
ユーザーに表示するための通常ページとメンテナンスページを配置します。 - CloudFormation
上記のリソースを作成します。
IsMaintenanceでメンテナンスのON/OFFを切り替えられます。
環境構築手順
1. CloudFormation テンプレート作成
以下の maintenance-stack.yaml として下記を保存します。
AWSTemplateFormatVersion: "2010-09-09"
Description: CloudFront + WAF + S3 Maintenance Page
Parameters:
IsMaintenance:
Type: String
AllowedValues:
- "true"
- "false"
Default: "false"
Description: Whether maintenance mode is enabled
AllowedIp:
Type: String
Default: "123.456.789.123/32"
Description: IP allowed during maintenance
Conditions:
IsMaintenanceEnabled: !Equals
- !Ref IsMaintenance
- "true"
Resources:
################################
# S3 Bucket (Maintenance Page)
################################
MaintenanceBucket:
Type: AWS::S3::Bucket
Properties:
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
################################
# CloudFront Origin Access Control
################################
CloudFrontOAC:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Name: maintenance-oac
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
################################
# Bucket Policy for CloudFront
################################
MaintenanceBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref MaintenanceBucket
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: cloudfront.amazonaws.com
Action: s3:GetObject
Resource: !Sub "${MaintenanceBucket.Arn}/*"
Condition:
StringEquals:
AWS:SourceArn: !Sub "arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}"
################################
# WAF IP Set
################################
MaintenanceIpSet:
Type: AWS::WAFv2::IPSet
Properties:
Name: maintenance-ipset
Scope: CLOUDFRONT
IPAddressVersion: IPV4
Addresses:
- !Ref AllowedIp
################################
# WAF Web ACL
################################
MaintenanceWebACL:
Type: AWS::WAFv2::WebACL
Properties:
Name: maintenance-webacl
Scope: CLOUDFRONT
DefaultAction:
Block: {}
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: maintenance-webacl
SampledRequestsEnabled: true
Rules:
- Name: AllowSpecificIP
Priority: 0
Action:
Allow: {}
Statement:
IPSetReferenceStatement:
Arn: !GetAtt MaintenanceIpSet.Arn
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: allow-ip
SampledRequestsEnabled: true
################################
# CloudFront Distribution
################################
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
DefaultRootObject: index.html
WebACLId: !If
- IsMaintenanceEnabled
- !GetAtt MaintenanceWebACL.Arn
- !Ref AWS::NoValue
Origins:
- Id: S3Origin
DomainName: !GetAtt MaintenanceBucket.RegionalDomainName
OriginAccessControlId: !Ref CloudFrontOAC
S3OriginConfig: {}
DefaultCacheBehavior:
TargetOriginId: S3Origin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
ForwardedValues:
QueryString: false
Cookies:
Forward: none
CustomErrorResponses: !If
- IsMaintenanceEnabled
-
- ErrorCode: 403
ResponseCode: 503
ResponsePagePath: /maintenance.html
ErrorCachingMinTTL: 0
- !Ref AWS::NoValue
Outputs:
CloudFrontDomainName:
Value: !GetAtt CloudFrontDistribution.DomainName
Description: CloudFront URL2. 通常ページとメンテナンスページ用のhtmlファイルの準備
以下のファイルを作成します。
- index.html(通常ページ)
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>通常ページ</title> </head> <body> <h1>通常ページです</h1> </body> </html>
- maintenance.html(メンテナンスページ)
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>メンテナンス中</title> </head> <body> <h1>現在メンテナンス中です</h1> <p>しばらくお待ちください。</p> </body> </html>
3. CloudFormationコードの適用
1.で作成したCloudFomrationテンプレートファイルによりAWS環境を構築します。
- 適用リージョン:us-east-1
※WAF(Scope: CLOUDFRONT)はus-east-1でのみ作成可能というAWS仕様上の制約があるため、単一のスタックで構築する場合は、us-east-1の指定が必要となる。 - スタック名:cloudfront-maintenance-stack ※任意の名称で作成してください
- パラメータ:
- IsMaintenance: “false”
- AllowedIp: “123.456.789.123/32”
※許可したいIPアドレスを指定してください。
4. S3 バケットへファイルアップロード
CloudFormation 適用後に作成される S3 バケットに2.で作成したindex.html(通常ページ)と maintenance.html(メンテナンスページ)をアップロードします。
メンテナンスページの表示と切り替え
動作を確認するために必要な準備は完了しましたので、実際のメンテナンス画面の切り替えの動作を確認します。
CloudFormation のパラメータ IsMaintenanceの値を切り替えることでメンテナンスページの切り替えができます。
メンテナンスモードを有効にする(ON)
AWS Managementコンソール上やAWS CLIによりCloudFormationテンプレートのパラメータをIsMaintenanceをtrueに変更します。
AWS CLIで実行する場合は、下記のようなコマンドでcloudformationを更新できます。
aws cloudformation update-stack \
--stack-name ${自身で作成したスタック名} \
--use-previous-template \
--parameters ParameterKey=IsMaintenance,ParameterValue=true \
ParameterKey=AllowedIp,UsePreviousValue=true上記を実行して、少し待ちますと、特定のIPアドレス以外のユーザからはメンテナンスページが表示されるようになりました。
ブラウザに入力するURLは、作成したCloudFrontのデフォルトドメインを指定しております。

メンテナンスモードを無効にする(OFF)
AWS Managementコンソール上やAWS CLIによりCloudFormationテンプレートのパラメータをIsMaintenanceをtrueに変更します。
AWS CLIで実行する場合は、下記のようなコマンドでcloudformationを更新できます。
aws cloudformation update-stack \
--stack-name ${自身で作成したスタック名} \
--use-previous-template \
--parameters ParameterKey=IsMaintenance,ParameterValue=false \
ParameterKey=AllowedIp,UsePreviousValue=true上記を実行して、少し待ちますと、通常ページが表示されるようになりました。

まとめ
本記事では、CloudFormationを活用して S3 + CloudFront + WAF によるメンテナンスモードの切り替え方法を紹介しました。
本記事は構成の一例を紹介しました。本内容が設計や実装のご参考になりましたら幸いです。
最後に考慮が必要な項目をまとめさせて頂きます。
- CloudFrontのキャッシュの影響
WAFの付け替え後に、CloudFrontのキャッシュにより古いページが表示される場合があります。
必要に応じて、CloudFrontのキャッシュの削除を行ってください。 - CloudFrontのメンテナンスページの切り替え時の遅延
CloudFormationでメンテナンスページのON・OFFを切り替えると、実行してから即時反映されるのではなく、少し時間をおいてから反映されますので、実際に試してみて動作を確認してください。 - メンテナンスページでスタイルシート(CSS)や画像を使用する場合
使用する必要がある場合は、対象のパスへのアクセス制限をしないようWAFのルールで設定が必要になります。 - 容量が小さいメンテナンスページの場合
WAFのカスタムレスポンスにおいて、4KB以下の場合、HTML形式で設定可能となりますので、あまりリッチなメンテナンス画面でない場合はWAFでメンテナンスページを完結することもできます。


