見出し画像

CloudFront ON Terraform

業務でCloudFrontを構築したので振り返りとCDN学習の為に備忘録を残しておきます。

 アジェンダ
1, cloudfrontとは
2, CDNとは
3, CDN概要
4, cloudfrontの用語集
5, terraformで表現する

CloudFrontとは?

cloud frontはエッジサービスとして位置付けされており、グローバルサービスである。AWSのリージョン外のサービスであることを忘れずに!
そしてリージョン外なのでuserに近いサービスと言える。各地にエッジロケーションが存在する。
なのでuserに一番近いエッジロケーションからコンテンツが配信される為、低レイテンシーなサービスを提供できる。

もっと深ぼって行くと、cloudfrontCDN(コンテンツデリバリーネットワーク)である。

CDNとは?

CDNとは「Content Delivery Network(コンテンツデリバリーネットワーク)」の略で、ウェブコンテンツを効率的かつスピーディーに配信できるように工夫されたネットワークのことです。

用途としてはオリジンサーバー(APサーバー)の負荷軽減として用いられます。userとオリジンサーバーの間にCDNを配置しオリジンからレスポンスされてコンテンツをキャッシュしておきます。
キャッシュすることで、2回目に同じリクエスがあり、コンテンツをレスポンスする際にキャッシュされたコンテンツをレスポンスします。それによって、オリジンサーバーの負荷は軽減されて、なおかつresponse timeが向上しレイテンシーの改善につながります。

AWSではこのCDNサービスを提供しているのがcloudfrontになります。

スクリーンショット_2021-08-01_21.06.42

※aws参考資料から抜粋※

CloudFrontの用語集

ビューワー(Viewer)
クライアント・webブラウザー

ディストリビューション(Distribution)
コンテンツ配信の設定単位

オリジン(origein)
コンテンツ提供元のサーバー、laravelの構成だとプロキシとして据えているnginx、はたまたS3をオリジンに据えたりと柔軟に対応ができる。

ビフェイビア(behavior)
キャッシュ動作設定、URLパスパターン毎に設定。

上記がキーとなるワードだ
一つ一つ構成要素をterraformのコードと一緒に見ていこう!

ディストリビューション

コンテンツ配信の構成設定を行う。オリジンの設定やら、ビフェイビアの設定やら。ちなみにオリジンの登録25個まで登録が可能。

下記のterraformのコードを見るかぎりdistributionの中にoriginやviewerやbehaviorの設定を記述していく

resource "aws_cloudfront_distribution" "assets" {
 enabled         = true
 is_ipv6_enabled = true
 comment         = "For ${var.project} Asset files(${var.env})"

 aliases = ["${var.sub_domain}${var.domain}"]

 viewer_certificate {
   cloudfront_default_certificate = false
   acm_certificate_arn            = aws_acm_certificate.cdn.arn
   minimum_protocol_version       = "TLSv1.2_2019"
   ssl_support_method             = "sni-only"
 }

 restrictions {
   geo_restriction {
     restriction_type = "none"
   }
 }

 origin {
   domain_name = aws_lb.web.dns_name
   origin_id   = "${var.env}-${var.project}-web-alb"

   custom_origin_config {
     http_port                = 80
     https_port               = 443
     origin_keepalive_timeout = 5
     origin_protocol_policy   = "https-only"
     origin_read_timeout      = 60

     origin_ssl_protocols = [
       "TLSv1.2",
     ]
   }
 }

 origin {
   domain_name = aws_s3_bucket.assets.bucket_regional_domain_name
   origin_id   = "S3-${aws_s3_bucket.assets.bucket}"

   s3_origin_config {
     origin_access_identity = aws_cloudfront_origin_access_identity.asset_origin_access_identity.cloudfront_access_identity_path
   }
 }

 origin {
   domain_name = aws_s3_bucket.uploads.bucket_regional_domain_name
   origin_id   = aws_s3_bucket.uploads.bucket

   s3_origin_config {
     origin_access_identity = aws_cloudfront_origin_access_identity.web_uploads.cloudfront_access_identity_path
   }
 }

 ordered_cache_behavior {
   path_pattern = "/public/*"

   allowed_methods = [
     "GET",
     "HEAD",
   ]

   cached_methods = [
     "GET",
     "HEAD",
   ]
   target_origin_id = "S3-${aws_s3_bucket.assets.bucket}"
   compress         = true
   default_ttl      = 86400
   max_ttl          = 259200
   min_ttl          = 0
   smooth_streaming = false
   trusted_signers  = []

   viewer_protocol_policy = "redirect-to-https"

   forwarded_values {
     headers = [
       "Accept",
       "Origin",
     ]
     query_string            = false
     query_string_cache_keys = []

     cookies {
       forward           = "none"
       whitelisted_names = []
     }
   }
 }

 ordered_cache_behavior {
   path_pattern = "/uploads/*"
   allowed_methods = [
     "GET",
     "HEAD",
   ]
   cached_methods = [
     "GET",
     "HEAD",
   ]
   compress               = false
   default_ttl            = 86400
   max_ttl                = 259200
   min_ttl                = 0
   smooth_streaming       = false
   target_origin_id       = aws_s3_bucket.uploads.bucket
   trusted_signers        = []
   viewer_protocol_policy = "redirect-to-https"

   forwarded_values {
     headers = [
       "Accept",
       "Origin",
     ]
     query_string            = false
     query_string_cache_keys = []

     cookies {
       forward           = "none"
       whitelisted_names = []
     }
   }
 }

 default_cache_behavior {
   viewer_protocol_policy = "redirect-to-https"
   min_ttl                = 0
   default_ttl            = 0
   max_ttl                = 0
   allowed_methods        = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
   cached_methods         = ["GET", "HEAD"]
   compress               = false
   target_origin_id       = "${var.env}-${var.project}-web-alb"
   forwarded_values {
     query_string = true
     headers      = ["*"]
     cookies {
       forward = "all"
     }
   }
 }
}


構成要素の一つずつ見ていく

> aliasesがすでに作成されたAレコード。
   こいつとcloudforntのDNS名が紐付いたCNAMEレコードを作成される。

>  事前準備としてroute53でAレコード、AAAレコード作成が必要。
 enabled         = true
 is_ipv6_enabled = true  -> IPv6も有効にしておくとIPv6のリクエストも受け付ける。
                                                           route53で作成が必要
 comment         = "For ${var.project} Asset files(${var.env})"
 
  aliases = ["${var.sub_domain}${var.domain}"]
viewer_certificateのTLS設定を行う。
SNIとは「Server Name Indication」の略で、SSL/TLSの拡張仕様の1つです。通常SSL証明書の設置には1つの証明書に対して1つの専用IPアドレスが必要となりますが、SNIを利用すると、1つのIPアドレスで複数のSSL証明書が設置可能となるため、専用IPアドレスが不要となります。

→前提としてcloudfrontのドメイン名とELBで使用するドメイン名は一緒であるのでsni-only設定が必要?(今後学習して修正します)
viewer_certificate {
   cloudfront_default_certificate = false
   acm_certificate_arn            = aws_acm_certificate.cdn.arn
   minimum_protocol_version       = "TLSv1.2_2019" ->どのTLSを有効かするか。ここは有無を言わず、
                                                                                                               最新のものを選択使用
   ssl_support_method             = "sni-only"  
 }
 > restrictions(地域制限)
特定の国のユーザーによるコンテンツへのアクセスを回避する必要がある場合は、CloudFront の地域制限を使用して設定ができる
restrictions {
   geo_restriction {
     restriction_type = "none" → 今回は制限なし
   }
 }

origin

origin今回オリジンの設定は ELB×1 s3×2 の3つ設定している。
dns_nameで当該のリソースを指定する。
・ custom_origin_configでオリジンの構成設定をする。
・s3の場合はs3_origin_configで定義
・s3をホストするにはオリジンアクセスアイデンティティ (OAI)が必要にな
 ります。s3アクセスするのはcloudfrontのURLのみ許可する場合はOAIを定
 義してそいつをoriginで紐付けます。このOAIを紐付けたら、
 S3のインラインポリシーでprincipalsでOAIを定義しときます。これで安全
 にアクセスが可能となります。
・ Origin Shieldという機能もあるけど、今後調べて修正します。
origin {
   domain_name = aws_lb.web.dns_name
   origin_id   = "${var.env}-${var.project}-web-alb"

   custom_origin_config {
     http_port                = 80
     https_port               = 443
     origin_keepalive_timeout = 5
     origin_protocol_policy   = "https-only"  -> https_onlyのにしとくべし。
																                                  ALBではリスナーではHttpsしか受け付けないように設定しとけば良い
     origin_read_timeout      = 60

     origin_ssl_protocols = [
       "TLSv1.2", -> TLSのバージョンは最新にね。
     ]
   }
 }

 origin {
   domain_name = aws_s3_bucket.assets.bucket_regional_domain_name
   origin_id   = "S3-${aws_s3_bucket.assets.bucket}"

   s3_origin_config {
     origin_access_identity = aws_cloudfront_origin_access_identity.asset_origin_access_identity.cloudfront_access_identity_path
   }
 }

 origin {
   domain_name = aws_s3_bucket.uploads.bucket_regional_domain_name
   origin_id   = aws_s3_bucket.uploads.bucket

   s3_origin_config {
     OAIの指定
     origin_access_identity = aws_cloudfront_origin_access_identity.web_uploads.cloudfront_access_identity_path
   }
 }

########
OAI
resource "aws_cloudfront_origin_access_identity" "asset_origin_access_identity" {
 comment = "${var.project} origin access identity for asset files"
}

resource "aws_cloudfront_origin_access_identity" "web_uploads" {
 comment = "${var.project} origin access identity for upload files"
}
##########

behavior

behavior
パスパターンやキャッシュ設定、ヘッダの設定をする
ordered_cache_behavior {          -> s3のbehaviorの設定。アセット
   path_pattern = "/uploads/*"
   allowed_methods = [
     "GET",
     "HEAD",
   ]
   cached_methods = [
     "GET",
     "HEAD",
   ]
   compress               = false
   default_ttl            = 86400
   max_ttl                = 259200
   min_ttl                = 0
   smooth_streaming       = false
   target_origin_id       = aws_s3_bucket.uploads.bucket
   trusted_signers        = []
   viewer_protocol_policy = "redirect-to-https"

   forwarded_values {
     headers = [
       "Accept",
       "Origin",
     ]
     query_string            = false
     query_string_cache_keys = []

     cookies {
       forward           = "none"
       whitelisted_names = []
     }
   }
 }

 default_cache_behavior {      -> デフォルトのbehavoir設定。パスパターンはariaceで定義されたもの/以下にはず。
   viewer_protocol_policy = "redirect-to-https"
   min_ttl                = 0
   default_ttl            = 0
   max_ttl                = 0
   allowed_methods        = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
   cached_methods         = ["GET", "HEAD"]
   compress               = false
   target_origin_id       = "${var.env}-${var.project}-web-alb" -> albをターゲットに
   forwarded_values {
     query_string = true
     headers      = ["*"]
     cookies {
       forward = "all"
     }
   }
allowed_methodst
HTTP メソッドを処理するよう CloudFront を構成すると、CloudFront はビューワーからの以下のリクエストを受け入れてカスタムオリジンに転送します。
DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT

今回はdefault_cache_behaviorで設定されているoriginサーバーはELBとなっており、その先に待ち構えているのはhttpサーバーなので上記を設定する.

ただ今回はsame originなのでoption headerとかいる?となるが、その受け入れはhttpサーバーが側で設定するはず!

以上ではありますが、振り返りは以上です。構築したコードを見直すのはいいことですね。webブラウザーセキュリティとかの本を読んだ後に、コードを見直すといろんな気づきがあります。。(勉強不足)

ここにはまだ記述してないですが、cloudfrontからの通信をhttps化にする際にTLSのリクエスト方法が少し変わっているので、今後記事を追記していこうと思います。

それではまた〜




この記事が気に入ったらサポートをしてみませんか?