cacheable_frontend pattern¶
概要¶
cacheable_frontend pattern
は、Amazon S3(以下、S3とする)に配置されたファイルを配信するためのモジュールです。
Amazon CloudFront(以下、CloudFrontとする)とAmazon Route 53(以下、Route 53とする)、そして前述のS3を利用します。
S3バケットに配置されたファイルを世界中のエッジロケーションでキャッシュすることにより、効率的にコンテンツを配信できるようになります。
環境構築後のS3バケットへのファイルのデプロイはcd_pipeline_frontendモジュールをご利用ください。
想定する適用対象環境¶
cacheable_frontend pattern
は、Runtime環境で使用されることを想定しています。
依存するpattern¶
cacheable_frontend pattern
は、事前に実行の必要なpatternはありません。ただし、AWS上で事前に以下を実施する必要があります。
- 独自ドメインの取得
- Route 53で上記ドメイン名のホストゾーン作成
CloudFrontでAWS WAFを利用したい場合は事前にAWS WAFを作成しておく(またはAWS WAF作成後にCloudFrontの設定変更をする)必要があります。 AWS WAFの作成はwebacl patternを利用することで行なえます。
構築されるリソース¶
このpatternでは、以下のリソースが構築されます。
リソース名 | 説明 |
---|---|
S3バケット | CloudFrontで配信するファイルを保存するバケット |
CloudFront Distribution | 世界中のエッジロケーションでファイルをキャッシュし、効率的にコンテンツを配信するサービス |
CloudFront Origin Access Identity | CloudFront Distribution がS3バケットにアクセスするためのリソース |
Route 53 レコード | CloudFront Distribution に名前でアクセスできるようにするためのDNSレコード |
AWS Certificate Manager | Route 53ホストゾーンのレコードに対するSSL/TLS証明書を発行するサービス |
Lambda@Edge | CloudFrontのイベントに応じて実行されるLambda関数 |
Amazon CloudWatch Logs | Lambda関数のログが置かれるロググループ |
AWS IAM | Lambda関数に付与する権限の設定 |
以下のリソースは構築されません。事前に手動での作成が必須になります。
リソース名 | 説明 |
---|---|
Route53 ホストゾーン | 事前取得済みのドメインに関するルーティングのレコードを管理するコンテナ |
モジュールの理解に向けて¶
CloudFrontを利用すると、S3バケットに配置されたファイルやELBでアクセス可能なコンテンツをキャッシュして効率的にコンテンツを配信できます。 具体的な配信の仕組みに関しては公式ドキュメントをご参照ください。
Eponaでは、ビルドした静的ファイルをS3バケットに配置し、Route 53とCloudFrontを使って独自ドメインでコンテンツを配信する利用方法を想定しています。 そのため、本patternを実行するためには事前に独自ドメインの取得が必須になります。
複数のリージョンへの対応¶
CloudFrontの利用には、SSL/TLS証明書が必要となります。WebサイトはHTTPSで公開するのが一般になりつつありますが、
CloudFrontの仕様として要求されます。
仮にHTTPで配信したい場合でも、CloudFrontにはSSL/TLS証明書が必要となることに注意してください。
cacheable_frontend pattern
には、下記のようなHTTPSでのWebサイト公開および、デプロイを踏まえた対応が組み込まれています。
CloudFrontとAWS Certificate Manager¶
cacheable_frontend pattern
では、SSL/TLS証明書をAWS Certificate Manager(以下ACMとする)で発行するように構成しています。
CloudFrontでACMの証明書を使う場合の要件として、バージニア北部リージョンで証明書を発行した証明書である必要があります。
静的コンテンツの更新¶
配信した静的コンテンツは、サービスの成長、改善にともない更新されていくでしょう。
Eponaでは、静的コンテンツの配信をcd_pipeline_frontend pattern
により構築されるCodePipelineで行います。
ここで構築されるパイプラインは、デプロイ先のS3バケットが同一リージョンにあることを想定しています。
cacheable_frontend pattern
では、これらの背景を踏まえた形で構築しています。
- CloudFrontとACMに関する要件
cd_pipeline_frontend pattern
との連携
つまりcacheable_frontend pattern
の利用にあたっては、リソースを配置するリージョンを意識する必要があります。
具体的には、cacheable_frontend pattern
では2つのProviderを使い分けを行います。用途は、それぞれ以下となります。
cache_provider
… CloudFrontに関連するリソースを扱う。バージニア北部リージョンが指定されることを想定origin_provider
… オリジンに関連するリソースを扱う。デフォルトリージョンが指定されることを想定
具体的な指定方法については、サンプルコードを参照してください。
CloudFrontのパラメータについて¶
CloudFrontは設定可能なパラメータの数が多いため、Terraform実行時に指定する変数の数も多くなっています。
各パラメータの意味や設定値に関しては公式ドキュメントを参照し、
Terraform実行時の変数の指定方法に関しては本ドキュメント下部のサンプルコードや
入出力リファレンスをご参照ください。
HTTPヘッダーについて¶
昨今のWebサイトはセキュリティの観点から特定のHTTPヘッダーをレスポンスヘッダーに含めることが推奨されています。
Eponaでもこの対応をCloudFrontに対して行えるようになっており、
AWS公式ドキュメント
に従ってLambda@Edgeを利用することで実現しています。
HTTPヘッダーについてはMDN Web Docsをご参照ください。
EponaではAWS公式のチュートリアル
を参考にして以下をLambdaのコードとしてデプロイしています。
デフォルトでLambda@Edgeにデプロイされるコード
ただし、Eponaの提供するLambdaでは最低限のセキュリティヘッダーしか付与しません。これは、各サービスにより必要なHTTPヘッダーも異なり、画一的な付与が困難なためです。サービスごとに必要なヘッダを検討の上、独自のLambdaのコードとしてデプロイすることを強く推奨します。
これを行う場合はviewer_response_lambda_source_dir
にコードを配置したローカルディレクトリのパスを指定してください。
相対パスで指定する場合は、Terraformを実行しているディレクトリをカレントディレクトリとして指定してください。
Single Page Application(SPA)のコンテンツを公開する¶
SPAではURLの変化に応じて表示するコンテンツを変化させるといった擬似的なページ遷移がよく使われます。 しかしCloudFrontの仕様1により、ファイルが存在しないURLへアクセスすると、返却されるHTTPステータスが404(NoSuchKey)になってしまうという事象が発生します。
これは、例えばステータスコードが404の場合にHTTPステータス200(OK)でエントリーポイントのコンテンツのパスを返すといったカスタムエラーレスポンスを設定することで回避できます。 以下に本patternを使ってこれを設定するサンプルを示します。
cloudfront_custom_error_responses = [
{
error_code = 404
error_caching_min_ttl = 300
response_code = 200
response_page_path = "/"
}
]
アクセスログの収集を行う¶
CloudFrontではアクセスログをS3バケットへ収集可能です。
これはオプションのため、明示的にロギングを設定しない場合は収集が行われません。
本patternを使ってアクセスログ収集を設定したい場合は、実行時に以下のように指定してください。
prefix
とinclude_cookies
オプションに関しての詳細は、それぞれ下記ページの「ログのプレフィックス」「Cookieのログ作成」をご参照ください。
cloudfront_logging_config = {
bucket_name = "アクセスログ収集先とするS3バケット名"
prefix = "sample"
include_cookies = true
}
地理的制限の有効化¶
CloudFrontでは国ごとにアクセスを制限する設定を行うことが可能ですが、本patternの現バージョンではこの設定は行えない仕様になっています。
Terraformでのリソース削除について¶
terraform apply
で作成したリソースは通常terraform destroy
でまとめて削除できます。
ただし、本patternでは一度目のterraform destroy
で必ず以下のエラーが発生し、一部のリソースが残ってしまう仕様になっています。
Error deleting Lambda Function: InvalidParameterValueException: Lambda was unable to delete arn:aws:lambda:us-east-1:XXXXXXXXXXXX:function:static-site-proxy:3 because it is a replicated function. Please see our documentation for Deleting Lambda@Edge Functions and Replicas.
status code: 400, request id: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
これはCloudFront
が完全にエッジロケーションから削除されるまでLambda@Edge
の削除を行えないというAWSの仕様によるものです。
Terraform公式の
Issue#1721
でもあがっており、現状では回避不可能となっています。
一度目のterraform destroy
後、数十分~数時間待ってから再度terraform destroy
を実行すると正常に削除できます。
サンプルコード¶
cacheable_frontend pattern
を使用したサンプルコードを、以下に記載します。
# Origin
provider "aws" {
alias = "origin_provider"
assume_role {
role_arn = "[TerraformExecutionRoleのARN]"
}
}
# CloudFrontやACMを配置するAWS Providerの定義(必ず、regionにはus-east-1を指定してください。)
provider "aws" {
alias = "cache_provider" # 任意の文字列
region = "us-east-1" # バージニア北部
assume_role {
role_arn = "[TerraformExecutionRoleのARN]"
}
}
module "cacheable_frontend" {
source = "git::https://gitlab.com/eponas/epona.git//modules/aws/patterns/cacheable_frontend?ref=v0.2.6"
# patternで利用するAWS Providerを定義
providers = {
# cache_providerには、CloudFrontに関連するリソースを扱うAWS Providerを定義
aws.cache_provider = aws.cache_provider
# origin_providerには、オリジンに関連するリソースを扱うAWS Providerを定義(ここではデフォルトProviderを指定)
aws.origin_provider = aws.origin_provider
}
s3_frontend_bucket_name = "test-epona-runtime-frontend-static"
zone_name = "example.com"
record_name = "test.example.com"
tags = {
Owner = "john"
Environment = "runtime"
RuntimeEnvironment = "development"
ManagedBy = "epona"
}
# カスタマイズしたResponse Header付与コードを使用する場合に指定
# 「customize_security_header」ディレクトリに配置した「sample.js」の「exports.handler」メソッドが実行される
viewer_response_lambda_source_dir = "./customize_security_header"
viewer_response_lambda_handler = "sample.handler"
viewer_response_lambda_log_retention_in_days = 90
cloudfront_default_root_object = "index.html"
cloudfront_http_version = "http2"
cloudfront_is_ipv6_enabled = false
cloudfront_price_class = "PriceClass_All"
cloudfront_web_acl_id = try(data.terraform_remote_state.webacl.outputs.webacl.webacl_arn, null) # webacl patternで作成したWebACLのARNを参照
cloudfront_origin = {
origin_path = "/hoge"
custom_headers = [
{
name : "foo"
value : "bar"
},
{
name : "test"
value : "sample"
}
]
}
cloudfront_default_cache_behavior = {
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
viewer_protocol_policy = "redirect-to-https"
min_ttl = null
default_ttl = null
max_ttl = null
compress = false
}
cloudfront_viewer_certificate = {
minimum_protocol_version = "TLSv1.2_2019"
}
cloudfront_custom_error_responses = [
{
error_code = 404
error_caching_min_ttl = 300
response_code = 200
response_page_path = "/"
}
]
cloudfront_logging_config = {
bucket_name = "test-epona-runtime-frontend-logging"
prefix = "sample"
include_cookies = false
}
}
関連するpattern¶
cacheable_frontend pattern
に関連するpatternを、以下に記載します。
pattern名 | 説明 |
---|---|
cd_pipeline_frontend | Runtime環境へのデプロイメントパイプラインを構築する |
webacl | Runtime環境へのAWS WAFリソースを作成する |
ログの集約¶
cacheable_frontend pattern
では、CloudFrontおよびS3に対するアクセスログを保存します。
保存場所は、どちらもS3となります。
これらのログは、datadog_log_trigger patternを使用することでDatadogに集約できます。
入出力リファレンス¶
Requirements¶
Name | Version |
---|---|
terraform | ~> 0.14.10 |
aws | >= 3.37.0, < 4.0.0 |
Inputs¶
Name | Description | Type | Default | Required |
---|---|---|---|---|
cloudfront_default_root_object | ルートへのアクセス時に表示させるファイル名(例: index.html ) |
string |
n/a | yes |
record_name | アプリケーションのエンドポイントとなるレコード名 | string |
n/a | yes |
s3_frontend_bucket_name | フロントの静的ファイルを配置する場所として作成するS3バケット名 | string |
n/a | yes |
zone_name | 事前作成済みのホストゾーン名 | string |
n/a | yes |
cloudfront_custom_error_responses | CloudFrontのエラーページアクセス時の動作設定 詳細はカスタムエラー応答の生成をご参照ください。 [ |
list(map(string)) |
[] |
no |
cloudfront_default_cache_behavior | CloudFrontのデフォルトのキャッシュ動作設定 | any |
{ |
no |
cloudfront_http_version | CloudFrontでサポートする最大のHTTPのバージョン(http1.1 or http2 ) |
string |
null |
no |
cloudfront_is_ipv6_enabled | CloudFrontでのIPv6有効化 | bool |
null |
no |
cloudfront_logging_bucket_force_destroy | destroy時にbucketとともに保存されているデータを強制的に削除可能にする。create_cloudfront_logging_bucket をtrueにしたときにのみ有効。 |
bool |
false |
no |
cloudfront_logging_config | CloudFrontのアクセスログの設定 アクセスログを収集したい場合は bucket_name の指定が必須CloudFormationでの指定方法と同様なため、詳細はCloudFormationのドキュメントをご参照ください。 |
map(string) |
{ |
no |
cloudfront_origin | CloudFrontの配信ソースの設定{ |
any |
{} |
no |
cloudfront_price_class | CloudFrontで利用する価格クラス(PriceClass_All or PriceClass_200 or PriceClass_100 ) |
string |
null |
no |
cloudfront_viewer_certificate | CloudFrontのSSL化の設定 | map(string) |
{ |
no |
cloudfront_web_acl_id | CloudFrontで利用するWebACLのARN | string |
null |
no |
create_cloudfront_logging_bucket | 新規にCloufFrontログ用のS3バケットを作成するか既存のバケットを使用するかを指定するフラグ(trueでバケットを新規に作成) | bool |
true |
no |
create_s3_access_log_bucket | 新規にS3アクセスログ用のS3バケットを作成するか既存のバケットを使用するかを指定するフラグ(trueでバケットを新規に作成) | bool |
true |
no |
enable_s3_access_log | S3へのアクセスをログとして記録する場合、trueを指定する | bool |
true |
no |
s3_access_log_bucket | S3へのアクセスログ保存用S3バケット名 | string |
null |
no |
s3_access_log_bucket_force_destroy | destroy時にbucketとともに保存されているデータを強制的に削除可能にする。create_s3_access_log_bucket をtrueにしたときにのみ有効。 |
bool |
false |
no |
s3_access_log_object_prefix | S3へのアクセスログ保存時に、オブジェクトに付与するprefix | string |
null |
no |
s3_frontend_bucket_force_destroy | フロントの静的ファイル配置用S3バケットにファイルがあっても、destroyでバケットごと強制削除できるようにする | bool |
false |
no |
tags | このモジュールで作成されるリソースに付与するタグ | map(string) |
{} |
no |
viewer_response_lambda_function_name | CloudFrontからのレスポンスにSecurityHeaderを付与するLambda関数の名前 | string |
"AddSecurityHeaderFunction" |
no |
viewer_response_lambda_handler | CloudFrontからのレスポンスにSecurityHeaderを付与するLambda関数のエントリーポイント | string |
"index.handler" |
no |
viewer_response_lambda_log_kms_key_id | CloudFrontからのレスポンスにSecurityHeaderを付与するLambda関数のログデータを暗号化するための、KMS CMKのARNを指定する | string |
null |
no |
viewer_response_lambda_log_retention_in_days | CloudFrontからのレスポンスにSecurityHeaderを付与するLambda関数がCloudWatch Logsへ出力するログの保存期間を設定する。 値は、次の範囲の値から選ぶこと: 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653. Resource: aws_cloudwatch_log_group / retention_in_days |
number |
3653 |
no |
viewer_response_lambda_runtime | CloudFrontからのレスポンスにSecurityHeaderを付与するLambda関数のランタイム | string |
"nodejs12.x" |
no |
viewer_response_lambda_source_dir | CloudFrontからのレスポンスにSecurityHeaderを付与するLambda関数のソースコードが配置されたディレクトリのパス(デフォルト以外のコードを使用したい場合に指定) | string |
null |
no |
viewer_response_lambda_timeout | 実行されたLambdaが停止するまでのタイムアウト設定。単位は秒で指定してください。 | number |
3 |
no |
Outputs¶
Name | Description |
---|---|
cloudfront_aliases | CloudFrontのドメインに設定した別名(CNAME) |
cloudfront_domain_name | CloudFrontのドメイン名 |
cloudfront_id | CloudFrontのID |
cloudfront_logging_bucket | CloudFrontのログ出力用のログ出力用のS3バケット名 |
cloudfront_logging_bucket_id | CloudFrontのログ出力用のS3バケットのID |
frontend_bucket_name | ビルド済みファイルを配置するバケットの名前 |
frontend_bucket_origin_path | ビルド済みファイルを配置するバケットのパス |
s3_access_log_bucket | S3へのアクセスログ出力用のS3バケット名 |
s3_access_log_bucket_id | S3へのアクセスログ出力用のS3バケットのID |
-
リクエストされたパスに相当するファイルを返し、ファイルが存在しない場合は404を返す ↩
※ このドキュメントはクリエイティブコモンズ(Creative Commons) 4.0 の「表示—継承」に準拠しています。
※ このドキュメントに記載されている会社名、製品名は、各社の登録商標または商標です。
© 2021 TIS Inc.