【速報】TerraformがCloudFrontに対応しました
はじめに
こんにちは、中山です。
先程Terraformのv0.6.15がリリースされましたね!
CHANGELOGはこちらです。さまざまなアップデートが含まれるのですが、やはりCloudFrontへの対応に目を引かれました。 aws_cloudfront_distribution
とaws_cloudfront_origin_access_identity
がCloudFront用のリソースです。以前のバージョンでもaws_cloudformation_stackリソースを使用すればCloudFrontの作成も可能でしたが、やはりリソースという形で対応してくれるとうれしいですね。
という訳で、早速使ってみたのでレポートしてみます。
インストール
まずはTerraformをインストールしましょう。
$ brew update $ brew cask install terraform
バージョンを確認します。
$ terraform version Terraform v0.6.15
TerraformでCache Distributionパターンを実装する
S3にオリジンの静的コンテンツを置いてCloudFrontでそのキャッシュを配信してみましょう。
コード
以下のコードを作成してください。
main.tf
variable "name" { default = "ap-northeast-1-cloudfront-resource-demo" } variable "region" { default = "ap-northeast-1" } variable "access_key" { } variable "secret_key" { } variable "acl" { default = "public-read" } variable "policy_file" { default = "policy.json.tpl" } variable "index" { default = "index.html" } provider "aws" { region = "${var.region}" access_key = "${var.access_key}" secret_key = "${var.secret_key}" } resource "aws_cloudfront_origin_access_identity" "origin_access_identity" { comment = "${var.name}" } resource "template_file" "s3_policy" { template = "${file(concat(path.module, "/", var.policy_file))}" vars { bucket_name = "${var.name}" origin_access_identity = "${aws_cloudfront_origin_access_identity.origin_access_identity.id}" } } resource "aws_s3_bucket" "s3" { bucket = "${var.name}" acl = "${var.acl}" force_destroy = true policy = "${template_file.s3_policy.rendered}" website { index_document = "${var.index}" } } resource "aws_s3_bucket_object" "s3" { bucket = "${aws_s3_bucket.s3.bucket}" key = "${var.index}" source = "${concat(path.module, "/", var.index)}" content_type = "text/html" } resource "aws_cloudfront_distribution" "cf" { enabled = true comment = "${var.name}" default_root_object = "${var.index}" price_class = "PriceClass_200" retain_on_delete = true origin { domain_name = "${concat(aws_s3_bucket.s3.id, ".s3.amazonaws.com")}" origin_id = "${var.name}" s3_origin_config { origin_access_identity = "${aws_cloudfront_origin_access_identity.origin_access_identity.cloudfront_access_identity_path}" } } default_cache_behavior { allowed_methods = ["GET", "HEAD"] cached_methods = ["GET", "HEAD"] target_origin_id = "${aws_s3_bucket.s3.id}" forwarded_values { query_string = false cookies { forward = "none" } } viewer_protocol_policy = "allow-all" min_ttl = 0 default_ttl = 3600 max_ttl = 86400 } restrictions { geo_restriction { restriction_type = "whitelist" locations = ["US", "CA", "GB", "DE", "JP"] } } viewer_certificate { cloudfront_default_certificate = true } } output "s3_website_endpoint" { value = "${aws_s3_bucket.s3.website_endpoint}" } output "cloudfront_domain_name" { value = "${aws_cloudfront_distribution.cf.domain_name}" }
policy.json.tpl
{ "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadForGetBucketObjets", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${origin_access_identity}" }, "Action": ["s3:GetObject"], "Resource": ["arn:aws:s3:::${bucket_name}/*"] } ] }
コードの解説
1. aws_cloudfront_origin_access_identity
今回はS3のエンドポイントへ直接アクセスさせない設定にするので、オリジンアクセスアイデンティティを作成します。オリジンアクセスアイデンティティを利用したS3バケットへのアクセス制限は、弊社甲木が書いた以下のエントリが参考になります。
2. template_file
バケットポリシーをテンプレートから作成しています。Terraform上の変数を ${variable}
という形式でテンプレートに埋め込み、それをレンダリングすることで変数の展開が可能です。
3. aws_s3_bucket
S3にバケットを作成します。Static Website Hosting機能を有効にさせ、ACLは public-read
に、バケットポリシーは作成するバケットに対して s3:GetObject
を許可させます。CloudFrontからのみコンテンツにアクセスさせたいのでPrincipleにはオリジンアクセスアイデンティティのIDを指定します。
4. aws_s3_bucket_object
作成したバケットにindex.htmlをアップロードします。
5. aws_cloudfront_distribution
最後にCloudFrontを作成します。詳細はドキュメントに詳しいですが、マネジメントコンソールでCloudFrontを作成した場合との対応表を以下に記述します。
Terraform上の設定 | Terraform上の値 | マネジメントコンソール上の設定 | マネジメントコンソール上の値 |
---|---|---|---|
enabled |
true |
Distribution State | Enabled |
comment |
ap-northeast-1-cloudfront-resource-demo |
Comment | ap-northeast-1-cloudfront-resource-demo |
default_root_object |
index.html |
Default Root Object | index.html |
price_class |
PriceClass_200 |
Price Class | Use Only US, Europe and Asia |
retain_on_delete |
true |
N/A(Terraform固有の機能) | N/A |
origin - domain_name |
ap-northeast-1-cloudfront-resource-demo.s3.amazonaws.com |
Origin Domain Name | ap-northeast-1-cloudfront-resource-demo.s3.amazonaws.com |
origin - origin_id |
ap-northeast-1-cloudfront-resource-demo |
Origin ID | ap-northeast-1-cloudfront-resource-demo |
origin - s3_origin_config - origin_access_identity |
origin-access-identity/cloudfront/ABC123 |
Origin Access Identity | origin-access-identity/cloudfront/ABC123 |
default_cache_behavior - allowed_methods |
["GET", "HEAD"] |
Allowed HTTP Methods | GET, HEAD |
default_cache_behavior - cached_methods |
["GET", "HEAD"] |
Cached HTTP Methods | GET, HEAD (Cached by default) |
default_cache_behavior - target_origin_id |
ap-northeast-1-cloudfront-resource-demo |
Origin | ap-northeast-1-cloudfront-resource-demo |
default_cache_behavior - forwarded_values - query_string |
false |
Forward Headers | None (Improves Caching) |
default_cache_behavior - forwarded_values - cookies - forward |
none |
Forward Cookies | None (Improves Caching) |
default_cache_behavior - viewer_protocol_policy |
allow-all |
Viewer Protocol Policy | HTTP and HTTPS |
default_cache_behavior - min_ttl |
0 |
Minimum TTL | 0 |
default_cache_behavior - default_ttl |
3600 |
Default TTL | 3600 |
default_cache_behavior - max_ttl |
86400 |
Maximum TTL | 86400 |
restrictions - geo_restriction - restriction_type |
whitelist |
Restriction Type | Whitelist |
restrictions - geo_restriction - locations |
["US", "CA", "GB", "DE", "JP"] |
Countries | CA -- CANADA DE -- GERMANY JP -- JAPAN GB -- UNITED KINGDOM US -- UNITED STATES |
viewer_certificate - cloudfront_default_certificate |
true |
SSL Certificate | Default CloudFront Certificate (*.cloudfront.net) |
実行する
まずオリジンコンテンツを設置します。今回はテスト目的なので簡易的なHTMLを設置するだけにします。
$ echo 'Hello, World!' > index.html
Terraformを実行します。 <access_key>
と <secret_key>
に自分のAWSクレデンシャルを指定してください。
$ terraform plan -var access_key=<access_key> -var secret_key=<secret_key> $ terraform apply -var access_key=<access_key> -var secret_key=<secret_key>
CloudFrontのStateがdeployedになるまで15分程度時間が掛かります。deployedになったらCloudFrontのドメインにアクセスしてみましょう。 <cloudfront-domain-name>
は自分の環境に合うよう修正してください。以下のようにHTTP/HTTPS両方でアクセスできたら成功です。
$ curl http://<cloudfront-domain-name> Hello World! $ curl https://<cloudfront-domain-name> Hello World!
逆に、以下のようにS3のエンドポイントへ直接アクセスして403が返ったら、バケットポリシーが意図したとおりに動作していると確認できます。
$ curl <s3-website-endpoint> <html> <head><title>403 Forbidden</title></head> <body> <h1>403 Forbidden</h1> <ul> <li>Code: AccessDenied</li> <li>Message: Access Denied</li> <li>RequestId: ABC123</li> <li>HostId: ABC123</li> </ul> <hr/> </body> </html>
まとめ
いかがだったでしょうか。
Terraformがどんどん便利になってうれしいですね。今後もアップデートを追いかけて行こうと思います。
本エントリがみなさんの参考になったら幸いに思います。