5
2

More than 1 year has passed since last update.

Terraform で CloudFront の OriginAccessIdentity から OriginAccessControl に変更する

Last updated at Posted at 2022-09-02

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_distributions3_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_identityidentifiers として許可します.

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中は以下のページになりコンテンツが表示されません.(ダウンタイム)

image.png

少し時間がかかりましたが, 無事変更できたようです 🎉

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)が選択されていますね.

image.png

S3バケットポリシーも大丈夫そうです.

image.png

コンテンツも見えています.

image.png

補足

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-modulesterraform-aws-cloudfrontは記事公開時点(9/2)で対応がまだのようですが,対応されたら試してみたいと思います.
https://github.com/terraform-aws-modules/terraform-aws-cloudfront

本記事が何かの参考になれば幸いです. 誤字・訂正などあれば編集リクエストください.

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2