Terraform で CloudFront の OriginAccessIdentity から OriginAccessControl に変更する
はじめに
2022/8/26(日本時間)に CloudFront の OriginAccessControl なる機能が追加されました.
この機能は以下の Terraform AWS Provider のバージョン4.29.0
にてTerraformで作成できるようになったので試してみました.
OACに関しての説明はこちらの記事がわかりやすいと思いますのでそちらを参照してください.
クラスメソッドさんの記事
https://dev.classmethod.jp/articles/amazon-cloudfront-origin-access-control/
Amazon Web Services ブログ
https://aws.amazon.com/jp/blogs/news/amazon-cloudfront-introduces-origin-access-control-oac/
本記事の内容で実施すると,ダウンタイムが発生します.移行手順ではないのでご注意ください.
Terraform構成
参考まで, 試した時の構成は次の通りです
CloudFrontは自前moduleを作り,
S3はterraform-aws-modules/s3-bucket/aws
を使用しています.
記事に関係ない部分は極力省略しています.
```
├── main.tf
├── outputs.tf
├── providers.tf
├── variables.tf
├── modules
│ └── cdn
│ ├── main.tf
│ ├── outputs.tf
│ ├── providers.tf
│ └── variables.tf
└── files
└── index.html
```
Terraformコード(Origin Access Identity)
お馴染みのOrigin Access Identity(以下,OAI) を使用して CloudFront と S3 を作成しておきます
CloudFront
リソースaws_cloudfront_origin_access_identity
を作成し, リソースaws_cloudfront_distribution
の s3_origin_config
を設定します.
aws_cloudfront_origin_access_identity
resource "aws_cloudfront_origin_access_identity" "main" {
comment = "oai-${var.name_suffix}"
}
aws_cloudfront_distribution
resource "aws_cloudfront_distribution" "main" {
origin {
connection_attempts = 3
connection_timeout = 10
domain_name = var.origin_domain_name
origin_id = "s3_one"
# origin_access_control_id = aws_cloudfront_origin_access_control.main.id
s3_origin_config {
origin_access_identity = aws_cloudfront_origin_access_identity.main.cloudfront_access_identity_path
}
}
aliases = [
"${var.subdomain}.${var.domain}"
]
enabled = true
is_ipv6_enabled = true
price_class = "PriceClass_200"
wait_for_deployment = true
web_acl_id = var.waf_arn
default_cache_behavior {
allowed_methods = ["GET", "HEAD", "OPTIONS"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "s3_one"
viewer_protocol_policy = "redirect-to-https"
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
}
restrictions {
geo_restriction {
restriction_type = "whitelist"
locations = ["JP"]
}
}
viewer_certificate {
acm_certificate_arn = var.acm_certificate_arn
ssl_support_method = "sni-only"
}
}
S3
また, S3バケットポリシーに aws_cloudfront_origin_access_identity
を identifiers
として許可します.
aws_iam_policy_document
data "aws_iam_policy_document" "s3_policy" {
statement {
actions = ["s3:GetObject"]
resources = ["${module.s3_bucket.s3_bucket_arn}/static/*"]
principals {
type = "AWS"
identifiers = [module.cdn.oai_iam_arn]
}
}
}
aws_s3_bucket_policy
resource "aws_s3_bucket_policy" "bucket_policy" {
bucket = module.s3_bucket.s3_bucket_id
policy = data.aws_iam_policy_document.s3_policy.json
}
Terraformコード(Origin Access Control)
先ほど作成したコードの一部を変更・追加して CloudFront から Origin Access Control (以下,OAC) を使用して S3 にアクセスを許可してみます.
リソースaws_cloudfront_origin_access_control
を作成し, リソース aws_cloudfront_distribution
の Origin Arguments にある origin_access_control_id
を設定します.
Resource: aws_cloudfront_distribution #origin_access_control_id
また, OAI で使用したs3_origin_config
は不要なのでコメントアウト(or 削除)しておきます.
aws_cloudfront_origin_access_control
resource "aws_cloudfront_origin_access_control" "main" {
name = "oac-${var.name_suffix}"
description = "Test migration OAI to OAC"
origin_access_control_origin_type = "s3"
signing_behavior = "always"
signing_protocol = "sigv4"
}
aws_cloudfront_distribution
resource "aws_cloudfront_distribution" "main" {
origin {
connection_attempts = 3
connection_timeout = 10
domain_name = var.origin_domain_name
origin_id = "s3_one"
origin_access_control_id = aws_cloudfront_origin_access_control.main.id # これを追加
# s3_origin_config { # こちらは不要なのでコメントアウト
# origin_access_identity = aws_cloudfront_origin_access_identity.main.cloudfront_access_identity_path
# }
}
aliases = [
"${var.subdomain}.${var.domain}"
]
enabled = true
is_ipv6_enabled = true
price_class = "PriceClass_200"
wait_for_deployment = true
web_acl_id = var.waf_arn
default_cache_behavior {
allowed_methods = ["GET", "HEAD", "OPTIONS"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "s3_one"
viewer_protocol_policy = "redirect-to-https"
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
}
restrictions {
geo_restriction {
restriction_type = "whitelist"
locations = ["JP"]
}
}
viewer_certificate {
acm_certificate_arn = var.acm_certificate_arn
ssl_support_method = "sni-only"
}
}
また, S3バケットポリシーは CloudFront のARNを指定して CloudFront からのアクセスを許可します.
data "aws_iam_policy_document" "s3_oac_policy" {
statement {
actions = ["s3:GetObject"]
resources = ["${module.s3_bucket.s3_bucket_arn}/static/*"]
principals {
type = "Service"
identifiers = ["cloudfront.amazonaws.com"]
}
condition {
test = "ForAnyValue:StringEquals"
variable = "AWS:SourceArn"
values = [module.cdn.cloudfront_distribution_arn]
}
}
}
resource "aws_s3_bucket_policy" "bucket_policy" {
bucket = module.s3_bucket.s3_bucket_id
policy = data.aws_iam_policy_document.s3_oac_policy.json
}
OAIからOACへの変更 plan
S3バケットポリシーとCloudFrontのOrigin部分が変更されるようですね.
Terraform will perform the following actions:
# aws_s3_bucket_policy.bucket_policy will be updated in-place
~ resource "aws_s3_bucket_policy" "bucket_policy" {
id = "cdn-test"
~ policy = jsonencode(
~ {
~ Statement = [
~ {
+ Condition = {
+ "ForAnyValue:StringEquals" = {
+ "AWS:SourceArn" = "arn:aws:cloudfront::xxxxxxxxxxxx:distribution/<ID>"
}
}
~ Principal = {
- AWS = "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <ID>" -> null
+ Service = "cloudfront.amazonaws.com"
}
# (4 unchanged elements hidden)
},
]
# (1 unchanged element hidden)
}
)
# (1 unchanged attribute hidden)
}
# module.cdn.aws_cloudfront_distribution.main will be updated in-place
~ resource "aws_cloudfront_distribution" "main" {
id = "<ID>"
tags = {}
# (19 unchanged attributes hidden)
- origin {
- connection_attempts = 3 -> null
- connection_timeout = 10 -> null
- domain_name = "cdn-test.s3.ap-northeast-1.amazonaws.com" -> null
- origin_id = "s3_one" -> null
- s3_origin_config {
- origin_access_identity = "origin-access-identity/cloudfront/<ID>" -> null
}
}
+ origin {
+ connection_attempts = 3
+ connection_timeout = 10
+ domain_name = "cdn-test.s3.ap-northeast-1.amazonaws.com"
+ origin_access_control_id = "<ID>"
+ origin_id = "s3_one"
}
# (3 unchanged blocks hidden)
}
Plan: 0 to add, 2 to change, 0 to destroy.
OAIからOACへの変更 apply
planで問題がなければ apply して反映します.
本記事の手順で実施すると, apply中は以下のページになりコンテンツが表示されません.(ダウンタイム)
少し時間がかかりましたが, 無事変更できたようです 🎉
Plan: 0 to add, 1 to change, 0 to destroy.
module.cdn.aws_cloudfront_distribution.main: Modifying... [id=xxxxxxxxxxx]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 10s elapsed]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 20s elapsed]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 30s elapsed]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 40s elapsed]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 50s elapsed]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 1m0s elapsed]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 1m10s elapsed]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 1m20s elapsed]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 1m30s elapsed]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 1m40s elapsed]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 1m50s elapsed]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 2m0s elapsed]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 2m10s elapsed]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 2m20s elapsed]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 2m30s elapsed]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 2m40s elapsed]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 2m50s elapsed]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 3m0s elapsed]
module.cdn.aws_cloudfront_distribution.main: Still modifying... [id=xxxxxxxxxxx, 3m10s elapsed]
module.cdn.aws_cloudfront_distribution.main: Modifications complete after 3m17s [id=xxxxxxxxxxx]
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
コンソールから確認します.
Origin access control settings (recommended)
が選択されていますね.
S3バケットポリシーも大丈夫そうです.
コンテンツも見えています.
補足
Origin Access Controlへの変更と同時にリソースaws_cloudfront_origin_access_identity
を削除試みようとすると使用中のエラーになりますので,変更が終わってから & 動作確認してから削除しましょう.
module.cdn.aws_cloudfront_origin_access_identity.main: Destroying... [id=xxxxxxxxxxxxxx]
╷
│ Error: CloudFrontOriginAccessIdentityInUse: The CloudFront origin access identity is still being used.
│ status code: 409, request id: xxxxxxxxxxxxxxx
おわりに
AWSのリリースから一週間程度でTerraformモジュールが対応されているのはほんと素早くてすごいですね.
terraform-aws-modules
のterraform-aws-cloudfront
は記事公開時点(9/2)で対応がまだのようですが,対応されたら試してみたいと思います.
https://github.com/terraform-aws-modules/terraform-aws-cloudfront
本記事が何かの参考になれば幸いです. 誤字・訂正などあれば編集リクエストください.