TerraformでCloudFront VPCオリジンの設定をしてみた

# Amazon CloudFront VPCオリジンとは

Amazon CloudFront VPCオリジンは、今年の11月にリリースされたCloudFrontの新機能です。

これまではALB、NLB、EC2等をオリジンにする場合はパブリックサブネットに配置する必要がありましたが、この機能によりプライベートサブネット内に配置できるようになりました。

https://aws.amazon.com/jp/blogs/news/introducing-amazon-cloudfront-vpc-origins-enhanced-security-and-streamlined-operations-for-your-applications/

# TerraformのAmazon CloudFront VPCオリジン対応

terraform-provider-awsのv5.82.0で `aws_cloudfront_vpc_origin` が追加され、TerraformでAmazon CloudFront VPCオリジンの設定が可能になりました。

https://github.com/hashicorp/terraform-provider-aws/releases/tag/v5.82.0

# Terraformでリソース作成

## テスト用のALBを作成

今回は簡単にテストするために固定レスポンスを返すALBをプライベートサブネット内に作成します。

以下、いくつかポイントについて説明します。

- ALBのセキュリティグループにCloudFrontのマネージドプレフィックスリストを利用したルールを追加してCloudFrontからのアクセスを許可しておく
    > Update your security groups for the VPC private origins to explicitly allow the CloudFront managed prefix list. For more information, see Use the CloudFront managed prefix list.
- インターネットからのトラフィックを受信するためにインターネットゲートウェイを作成する
    > Internet gateway – Required so that your VPC can receive traffic from the internet. The internet gateway is not used for routing traffic to origins inside the subnet, and you don’t need to update the routing policies.

その他の要件についてはドキュメントを参照してください。
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-vpc-origins.html

    
```hcl
locals {
  availability_zones = [
    "ap-northeast-1a",
    "ap-northeast-1c",
    "ap-northeast-1d",
  ]
}

data "aws_ec2_managed_prefix_list" "cloudfront" {
  name = "com.amazonaws.global.cloudfront.origin-facing"
}

resource "aws_vpc" "this" {
  cidr_block = "10.0.0.0/16"
}

# インターネットからのトラフィックを受信するために必要
# 存在しないとVPCオリジン作成時にエラーになります。
resource "aws_internet_gateway" "this" {
  vpc_id = aws_vpc.this.id
}

resource "aws_subnet" "this" {
  for_each = toset(local.availability_zones)

  vpc_id            = aws_vpc.this.id
  availability_zone = each.key
  cidr_block        = cidrsubnet(aws_vpc.this.cidr_block, 8, index(local.availability_zones, each.key))
}

resource "aws_security_group" "private_alb" {
  vpc_id = aws_vpc.this.id

  ingress {
    from_port       = 80
    to_port         = 80
    protocol        = "tcp"
    # CloudFrontからのアクセスを許可
    prefix_list_ids = [data.aws_ec2_managed_prefix_list.cloudfront.id]
  }
}

resource "aws_lb" "private_alb" {
  name               = "private-alb"
  internal           = true
  load_balancer_type = "application"
  security_groups    = [aws_security_group.private_alb.id]
  subnets            = [for subnet in aws_subnet.this : subnet.id]
}

resource "aws_lb_listener" "private_alb" {
  load_balancer_arn = aws_lb.private_alb.arn
  port              = 80
  protocol          = "HTTP"

  default_action {
    type = "fixed-response"

    fixed_response {
      content_type = "text/plain"
      message_body = "Hello"
      status_code  = "200"
    }
  }
}
```


# VPCオリジンとディストリビューションを作成

ALBを指定してVPCオリジンを作成し、ディストリビューションにVPCオリジンをオリジンとして設定します。

```hcl
resource "aws_cloudfront_vpc_origin" "private_alb" {
  vpc_origin_endpoint_config {
    name                   = "private-alb"
    arn                    = aws_lb.private_alb.arn
    http_port              = 80
    https_port             = 443
    origin_protocol_policy = "http-only"

    origin_ssl_protocols {
      quantity = 1
      items    = ["TLSv1.2"]
    }
  }
}

resource "aws_cloudfront_distribution" "private_alb" {
  origin {
    origin_id   = "private_alb"
    domain_name = aws_lb.private_alb.dns_name
    vpc_origin_config {
      vpc_origin_id = aws_cloudfront_vpc_origin.private_alb.id

    }
  }

  enabled = true

  default_cache_behavior {
    allowed_methods  = ["GET", "HEAD"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = "private_alb"

    forwarded_values {
      query_string = false

      cookies {
        forward = "none"
      }
    }

    viewer_protocol_policy = "redirect-to-https"
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }
}

```

`terraform apply` してリソースを作成し、作成されたディストリビューションにアクセスすると、ALBにレスポンスとして設定した `Hello` という文字列が返ってくることが確認できます。



# まとめ

Terraformで比較的簡単にCloudFront VPCオリジンの設定ができることを確認できました。
今後、CloudFrontを使用する際に活用していきたいと思います！