Amazon CloudFront の Origin Access Identity を Origin Access Control (OAC) に切り替える。Terraform編。

記事タイトルとURLをコピーする

こんにちは。
技術課の山本です。

夏休みは北アルプスをお散歩していました。お気に入りの黒部五郎岳です。

以下の記事で、Amazon CloudFront の Origin Access Identity を Origin Access Control (OAC) に切り替える方法をご案内しました。

blog.serverworks.co.jp

Terraform も Origin Access Control (OAC) に対応しましたので、本記事で紹介します。
AWS Provider 4.29.0 以降のバージョンがOACに対応しています。
具体的には、以下が可能になっています。

  • Origin Access Control (OAC) を作成可能になった
  • Origin Access Control (OAC) をCloudFront ディストリビューションのS3オリジンに紐づけることが可能になった

FEATURES:
New Resource: aws_cloudfront_origin_access_control (#26508)

ENHANCEMENTS:
resource/aws_cloudfront_distribution: Add origin_access_control_id to the origin configuration block (#26510)

ご参考1:v4.29.0
ご参考2:CHANGELOG

Origin Access Control (OAC) を作成するコード。

Origin Access Control (OAC) を作成します。
公式ドキュメント:cloudfront_origin_access_control

resource "aws_cloudfront_origin_access_control" "example" {
  name                              = "example"
  description                       = "example"
  origin_access_control_origin_type = "s3"
  signing_behavior                  = "always"
  signing_protocol                  = "sigv4"
}

Origin Access Control (OAC) をCloudFront ディストリビューションのS3オリジンに紐づけるコード。

元々あったOrigin Access Identity をコメントアウトし、Origin Access Control (OAC) をCloudFront ディストリビューションのS3オリジンに紐づけます。
公式ドキュメント:cloudfront_distribution

resource "aws_cloudfront_distribution" "s3_distribution" {
  origin {
    domain_name = aws_s3_bucket.b.bucket_regional_domain_name
    origin_id   = local.s3_origin_id
    # Origin Access Control (OAC) を紐づける。
    origin_access_control_id = aws_cloudfront_origin_access_control.example.id
    # 元々あったOrigin Access Identity をコメントアウト
    #s3_origin_config {
    #  origin_access_identity = aws_cloudfront_origin_access_identity.example.cloudfront_access_identity_path
    #}
  }

S3 のバケットポリシーを更新するコード。

CloudFront を更新している最中に、WEBサイトに接続しているユーザーが、Origin Access Identity で 引き続きS3 オリジンのコンテンツに接続できるようにします。
そのために、元々のポリシーを残しておきます。
1つ目の statement は Origin Access Control (OAC) 用に新規作成したものです。
2つ目の statement は Origin Access Identity 用に元々あったものです。
2つ目のステートメントは Origin Access Control (OAC) への切り替え後に削除します。

resource "aws_s3_bucket_policy" "example" {
  bucket = aws_s3_bucket.b.id
  policy = data.aws_iam_policy_document.example.json
}

data "aws_iam_policy_document" "example" {
  statement {
    principals {
      type        = "Service"
      identifiers = ["cloudfront.amazonaws.com"]
    }
    actions   = ["s3:GetObject"]
    resources = ["${aws_s3_bucket.b.arn}/*"]
    condition {
      test     = "StringEquals"
      variable = "aws:SourceArn"
      values   = [aws_cloudfront_distribution.s3_distribution.arn]
    }
  }
  statement {
    principals {
      type        = "AWS"
      identifiers = [aws_cloudfront_origin_access_identity.example.iam_arn]
    }
    actions   = ["s3:GetObject"]
    resources = ["${aws_s3_bucket.b.arn}/*"]
  }
}

Origin Access Control (OAC) への切り替え。

Origin Access Control (OAC) への切り替えをしていきます。

terraform plan
terraform apply

完了しました。

反映されています。
Origin Access Control (OAC)ができています。
Origin Access Control (OAC) がCloudFront ディストリビューションのS3オリジンに紐づいています。
S3のバケットポリシーも反映できています。

WEBサイトに正常にアクセスできることが確認できたら、S3 のバケットポリシーから、Origin Access Identity 用のステートメントを削除します。
Origin Access Identity 用のステートメントを削除したコードは以下です。削除箇所がわかりやすいようにコメントアウトしています。

data "aws_iam_policy_document" "example" {
  statement {
    principals {
      type        = "Service"
      identifiers = ["cloudfront.amazonaws.com"]
    }
    actions   = ["s3:GetObject"]
    resources = ["${aws_s3_bucket.b.arn}/*"]
    condition {
      test     = "StringEquals"
      variable = "aws:SourceArn"
      values   = [aws_cloudfront_distribution.s3_distribution.arn]
    }
  }
  #statement {
  #  principals {
  #    type        = "AWS"
  #    identifiers = [aws_cloudfront_origin_access_identity.example.iam_arn]
  #  }
  #  actions   = ["s3:GetObject"]
  #  resources = ["${aws_s3_bucket.b.arn}/*"]
  #}
}

また、Origin Access Identity 自体も削除します。削除箇所がわかりやすいようにコメントアウトしています。

#resource "aws_cloudfront_origin_access_identity" "example" {}

環境に反映していきます。

terraform plan
terraform apply

完了しました。

S3のバケットポリシーも反映できています。

WEBサイトに正常にアクセスできることを確認します。
以上で完了です。

サンプルコード

この記事を書くにあたり、検証したサンプルコードを記載します。
検証等にご利用ください。
概ね、以下の公式ドキュメントにあるサンプルを流用しています。
公式ドキュメント1:cloudfront_origin_access_control
公式ドキュメント2:cloudfront_distribution

resource "aws_s3_bucket" "b" {
  bucket = "mybucket-testtesttesttesttesttet"
}

resource "aws_s3_bucket_acl" "b_acl" {
  bucket = aws_s3_bucket.b.id
  acl    = "private"
}

locals {
  s3_origin_id = "myS3Origin"
}

#resource "aws_cloudfront_origin_access_identity" "example" {}

resource "aws_cloudfront_distribution" "s3_distribution" {
  origin {
    domain_name = aws_s3_bucket.b.bucket_regional_domain_name
    origin_id   = local.s3_origin_id
    origin_access_control_id = aws_cloudfront_origin_access_control.example.id
    #s3_origin_config {
    #  origin_access_identity = aws_cloudfront_origin_access_identity.example.cloudfront_access_identity_path
    #}
  }

  enabled             = true
  is_ipv6_enabled     = true
  comment             = "Some comment"
  default_root_object = "index.html"

  default_cache_behavior {
    allowed_methods  = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = local.s3_origin_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        = ["JP","US", "CA", "GB", "DE"]
    }
  }

  price_class = "PriceClass_200"
  viewer_certificate {
    cloudfront_default_certificate = true
  }
}

resource "aws_cloudfront_origin_access_control" "example" {
  name                              = "example"
  description                       = "example"
  origin_access_control_origin_type = "s3"
  signing_behavior                  = "always"
  signing_protocol                  = "sigv4"
}

resource "aws_s3_bucket_policy" "example" {
  bucket = aws_s3_bucket.b.id
  policy = data.aws_iam_policy_document.example.json
}

data "aws_iam_policy_document" "example" {
  statement {
    principals {
      type        = "Service"
      identifiers = ["cloudfront.amazonaws.com"]
    }
    actions   = ["s3:GetObject"]
    resources = ["${aws_s3_bucket.b.arn}/*"]
    condition {
      test     = "StringEquals"
      variable = "aws:SourceArn"
      values   = [aws_cloudfront_distribution.s3_distribution.arn]
    }
  }
  #statement {
  #  principals {
  #    type        = "AWS"
  #    identifiers = [aws_cloudfront_origin_access_identity.example.iam_arn]
  #  }
  #  actions   = ["s3:GetObject"]
  #  resources = ["${aws_s3_bucket.b.arn}/*"]
  #}
}

山本 哲也 (記事一覧)

カスタマーサクセス部のエンジニア(一応)

好きなサービス:ECS、ALB

趣味:トレラン、登山(たまに)