😄

TerraformでS3+CloudFrontで画像配信を構築するメモ

2024/11/12に公開

TerraformでS3+CloudFrontで画像配信システムを構築するメモ

TerraformでS3とCloudFrontを使用して画像配信システムを構築した時のメモ
まずZenn記事の記事を参考にしてOAIでCloudFrontからS3の画像ファイルにアクセスできるかを確認した後実施した。

Terraformのコード

プロバイダーの設定

provider "aws" {
  region = "ap-northeast-1"
}

S3関連

## バケットの作成
resource "aws_s3_bucket" "test_article_bucket1" {
  bucket = "test-article-bucket1"

  tags = {
    Name = "test-article-bucket1"
    Environment = "development"
  }
}

## バケットの所有権制御
resource "aws_s3_bucket_ownership_controls" "test_article_ownership_controls" {
  bucket = aws_s3_bucket.test_article_bucket1.id

  rule {
    object_ownership = "BucketOwnerPreferred"
  }
}

## バケットとバケットポリシーの紐付け
resource "aws_s3_bucket_policy" "allow_cloudfront_access" {
  bucket = aws_s3_bucket.test_article_bucket1.id
  policy = data.aws_iam_policy_document.allow_cloudfront_access.json
}

## バケットポリシー
data "aws_iam_policy_document" "allow_cloudfront_access" {
  version = "2008-10-17"
  
  statement {
    sid    = "AllowCloudFrontServicePrincipal"
    effect = "Allow"
    
    principals {
      type = "Service"
      identifiers = ["cloudfront.amazonaws.com"]
    }
    
    actions = ["s3:GetObject"]
    
    resources = ["${aws_s3_bucket.test_article_bucket1.arn}/*"]
    
    condition {
      test     = "StringEquals"
      variable = "AWS:SourceArn"
      values   = ["arn:aws:cloudfront::AWSアカウントのID:distribution/${aws_cloudfront_distribution.test_article_distribution.id}"]
    }
  }
}

CloudFront

## ディストリビューションの作成
resource "aws_cloudfront_distribution" "test_article_distribution" {
  enabled = true
  
  origin {
    origin_id = aws_s3_bucket.test_article_bucket1.id
    domain_name = aws_s3_bucket.test_article_bucket1.bucket_regional_domain_name
    origin_access_control_id = aws_cloudfront_origin_access_control.test_article_oac.id
  }

  default_cache_behavior {
    allowed_methods = ["GET", "HEAD"]
    cached_methods = ["GET", "HEAD"]
    target_origin_id = aws_s3_bucket.test_article_bucket1.id

    forwarded_values {
      query_string = false
      cookies {
        forward = "none"
      }
    }

    viewer_protocol_policy = "redirect-to-https"
    min_ttl = 0
    default_ttl = 86400
    max_ttl = 31536000
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }
}

## OACの作成
resource "aws_cloudfront_origin_access_control" "test_article_oac" {
  name = "test_article_oac"
  description = "test oac"
  origin_access_control_origin_type = "s3"
  signing_behavior = "always"
  signing_protocol = "sigv4"
}

全部

################################################
# プロバイダーの設定
################################################
provider "aws" {
  region = "ap-northeast-1"
}

################################################
# S3
################################################

## バケットの作成
resource "aws_s3_bucket" "test_article_bucket1" {
  bucket = "test-article-bucket1"

  tags = {
    Name = "test-article-bucket1"
    Environment = "development"
  }
}

## バケットの所有権制御
resource "aws_s3_bucket_ownership_controls" "test_article_ownership_controls" {
  bucket = aws_s3_bucket.test_article_bucket1.id

  rule {
    object_ownership = "BucketOwnerPreferred"
  }
}

## バケットとバケットポリシーの紐付け
resource "aws_s3_bucket_policy" "allow_cloudfront_access" {
  bucket = aws_s3_bucket.test_article_bucket1.id
  policy = data.aws_iam_policy_document.allow_cloudfront_access.json
}

## バケットポリシー
data "aws_iam_policy_document" "allow_cloudfront_access" {
  version = "2008-10-17"
  
  statement {
    sid    = "AllowCloudFrontServicePrincipal"
    effect = "Allow"
    
    principals {
      type = "Service"
      identifiers = ["cloudfront.amazonaws.com"]
    }
    
    actions = ["s3:GetObject"]
    
    resources = ["${aws_s3_bucket.test_article_bucket1.arn}/*"]
    
    condition {
      test     = "StringEquals"
      variable = "AWS:SourceArn"
      values   = ["arn:aws:cloudfront::AWSアカウントのID:distribution/${aws_cloudfront_distribution.test_article_distribution.id}"]
    }
  }
}

################################################
# CloudFront
################################################

## ディストリビューションの作成
resource "aws_cloudfront_distribution" "test_article_distribution" {
  enabled = true
  
  origin {
    origin_id = aws_s3_bucket.test_article_bucket1.id
    domain_name = aws_s3_bucket.test_article_bucket1.bucket_regional_domain_name
    origin_access_control_id = aws_cloudfront_origin_access_control.test_article_oac.id
  }

  default_cache_behavior {
    allowed_methods = ["GET", "HEAD"]
    cached_methods = ["GET", "HEAD"]
    target_origin_id = aws_s3_bucket.test_article_bucket1.id

    forwarded_values {
      query_string = false
      cookies {
        forward = "none"
      }
    }

    viewer_protocol_policy = "redirect-to-https"
    min_ttl = 0
    default_ttl = 86400
    max_ttl = 31536000
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }
}

## OACの作成
resource "aws_cloudfront_origin_access_control" "test_article_oac" {
  name = "test_article_oac"
  description = "test oac"
  origin_access_control_origin_type = "s3"
  signing_behavior = "always"
  signing_protocol = "sigv4"
}

これでS3のオブジェクトのURLにアクセスするとAccess Deniedというエラーメッセージが表示され、CloudFrontのURL/ファイル名にアクセスすると写真が表示される

参考

最後に

間違っていることがあれば、コメントに書いていただけると幸いです。
よろしくお願いいたします。

GitHubで編集を提案

Discussion