#1. はじめに
以下の画像が何かわかりますでしょうか?
そうです。署名付きクッキーで制限したCloudFrontにアクセスした際、クッキーが正しく設定でいていない時に表示されるエラーです。わかりましたか?
さて、署名付きクッキーがない時に毎回この画面が表示されたんじゃ中々ばつが悪いことがあります。特に、「ログインページからログインして(署名付きクッキーを設定して)ページに飛べば正常通りに表示されるのに、直接URLで入ったらこんな画面が表示された。。。」なんて思われてしまうかも。。。ちなみに、署名付きクッキーとは公式ではこういったものです。
#2. カスタムエラーレスポンスの設定
カスタムエラーレスポンスとは何でしょうか。簡単に言うと、CloudFrontディストリビューションにアクセスした際に上記のようなエラー画面ではなく、自分で設定した画面を表示する処理を行う設定になります。公式の説明はこちらへ。
ではでは、カスタムエラーレスポンスの設定を行いましょう.
まず前提として、エラーが発生した場合に飛ばすログイン画面は、S3の'/login/inedx.html'に格納されているとしましょう。署名付きクッキーでディストリビューションへのアクセスを制限している場合、パス'/login/'への制限がないようにビヘイビアを編集する必要があります。
###やり方1 直接ログインページを表示する
こちらは、エラーが発生したページで直接ログインページを開くやり方になります。下記とは違い、エラーが発生したページのURLのまま、ログインページを開くことになります。
手順としては、任意のディストリビューションを選択し、エラーページのカスタムエラーレスポンスの作成を選択します。今回対象となるエラーは認証情報が足りない場合の403エラーになるため、エラーコードで403を選択します。最小TTLのキャッシュエラーは、変に残っていると再度アクセスした際に認証情報が足りててもログインページに飛ぶことがあるため0にしました。レスポンスページのパスでは表示したい'/login/index.html'を選択します。HTTPレスポンスコードはHTTPエラーコードと同様の403を選択しましょう。200を選択した場合、ログインページがそのURLにキャッシュとして残り、何度アクセスしてもログインページが表示されるようになります。
カスタムエラーレスポンスの作成をクリックして作成しましょう。これで403エラーが発生した時に/login/inedx.htmlが表示されるようになりました。
しかし、先ほども言ったようにこのやり方はエラーが発生したページのURLのまま、ログインページを表示します。/login/inedx.htmlで他の画像などを参照していた場合、参照元URLが変わるため、相対パスで参照していた場合うまく他の情報を参照できなくなります。そこで、/login/inedx.htmlの参照先を絶対パスに変更しておきましょう。
###やり方2 ログインページにリダイレクトさせる
こちらは、エラーが発生した際にそのURLで別のページを開いて、ログインページにリダイレクトさせるやり方になります。上記とは違い、どのページでエラーが発生しても、ログインページのURLでログインページが表示されます。
やり方は手順は1とほとんど同じです。ただし、一度別のページを開く必要があるため、S3'/error/error.html'にログインページにログイン画面に飛ばすよう仕込んでおく必要があります。
まずは、カスタムエラーレスポンスの設定を行いましょう。下記の画像のように設定すればOKです。
次に、パス'/error/'への制限がないようにビヘイビアを編集します。最後にS3/error/'の中に下記のように書きerror.htmlを格納しましょう。
error.html
<!DOCTYPE html>
<html lang="ja">
<title>403</title>
<script>location.href='https://~~~~/login/index.html'</script>
これで、403エラー時に/error/error.htmlにアクセスし、'/login/index.html'に飛ばされるようになりました。
ちなみに、もしもIEでこの動作を行いたい場合は注意が必要です。IEでは、設定されているエラーページが500バイト以下の場合に、IEで標準に設定されているエラーページを表示するという仕様があります。なので、もしIEでも使用される場合は、error.htmlを下記のように訂正します。
error.html
<!DOCTYPE html>
<html lang="ja">
<title>403</title>
<script>location.href='https://~~~~/login/index.html'</script>
<a>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</a>
上記のerror.htmlをS3に格納した時に500バイトを超えるまで「a」を適当に増やしてください。
#3. CloudFormationでも設定方法
CloudFormationのテンプレートを用いて、カスタムエラーレスポンスの設定を行ってみました。手順1の場合、AWS::CloudFront::DistributionプロパティのDistributionConfigに下記のように設定を追加すればOKです。
CustomErrorResponses:
- ErrorCachingMinTTL: 0
ErrorCode: 403
ResponseCode: 403
ResponsePagePath: /login/index.html
せっかくなんで、CloudFront全体のテンプレートファイルを公開します。すでにS3は作成済、バケットポリシーは何も記入無し、ACMに証明書登録済という前提で行います。やり方は手順1、アクセス制限は署名付きクッキーで行います。また、他の設定項目はおおむね適当です。すきに設定してください。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
Create CloudFront Distribution
Resources:
#S3とCloudFrontを繋ぐようのOAI
CloudFrontOriginAccessIdentity:
Type: "AWS::CloudFront::CloudFrontOriginAccessIdentity"
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: access-identity-<S3バケット名>
#S3に追記するバケットポリシー
BucketPolicy:
Type: "AWS::S3::BucketPolicy"
Properties:
Bucket: <S3バケット名>
PolicyDocument:
Statement:
- Action: "s3:GetObject"
Effect: Allow
Resource: arn:aws:s3:::<S3バケット名>/*
Principal:
CanonicalUser: !GetAtt CloudFrontOriginAccessIdentity.S3CanonicalUserId
#クラウドフロントディストリビューション作成
CloudFrontDistribution:
Type: "AWS::CloudFront::Distribution"
Properties:
DistributionConfig:
Comment: <コメント>
#証明書関係
ViewerCertificate:
AcmCertificateArn: <証明書のarm>
MinimumProtocolVersion: TLSv1.2_2019
SslSupportMethod: sni-only
PriceClass: PriceClass_All
#オリジンの設定 S3との接続の設定
Origins:
- DomainName: <S3バケット名>.s3.amazonaws.com
Id: S3origin-<S3バケット名>
S3OriginConfig:
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}"
#Behaviorsの設定 著名付クッキー等の設定
DefaultCacheBehavior: #デフォルトの接続の設定
TargetOriginId: S3origin-<S3バケット名>
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
DefaultTTL: 3600
MaxTTL: 86400
MinTTL: 60
Compress: true
ForwardedValues:
QueryString: false
TrustedKeyGroups:
- <署名付きクッキーのキー>
CacheBehaviors:
- TargetOriginId: S3origin-<S3バケット名> #login/*の接続の設定
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
DefaultTTL: 3600
MaxTTL: 86400
MinTTL: 60
Compress: true
ForwardedValues:
QueryString: false
PathPattern: login/*
#カスタムエラーレスポンスの設定
CustomErrorResponses:
- ErrorCachingMinTTL: 0
ErrorCode: 403
ResponseCode: 403
ResponsePagePath: /login/index.html
HttpVersion: http2
Enabled: true
#4. 終わりに
いかがだったでしょうか。カスタムエラーレスポンスの設定よりも、CloudFrontのテンプレートファイルの方が需要があるかもしれませんね。。。今回紹介しているカスタムエラーレスポンスでは、署名付きクッキーがない際の403エラーを例に挙げていますが、他にもWAFによるエラー等も使用できると思われますので、ぜひ使用してみてください。