Cloudfront 와 S3 구성하기

Cloudfront와 S3를 활용하여 static한 페이지 구성하기

AWS Cloudfront + S3

보통 정적 컨텐츠를 저장할 목적으로 S3를 많이 활용합니다. 이렇게 저장한 파일은 S3 자체에서 제공할수도 있지만, 비용 절감과 속도 향상을 위해서 CDN(Contents Delivery Network)을 사용합니다. AWS에서는 Cloudfront라는 대표적인 서비스를 제공하는데, 본 실습에서는 이 Cloudfront와 S3를 연동하여 한 번에 생성해보도록 하겠습니다.

Backend 구성

terraform/s3/art-id/id_apnortheast2/backend.tf
terraform {
  required_version = ">= 1.0.0"

  backend "s3" {
    bucket         = "art-id-apnortheast2-tfstate"
    key            = "art/terraform/s3/art-id/id_apnortheast2/terraform.tfstate"
    region         = "ap-northeast-2"
    encrypt        = true
    dynamodb_table = "terraform-lock"
  }
}

도메인을 보유하지 않은 경우

  • CloudFront의 경우, 자신이 원하는 도메인을 설정할 수 있습니다.

  • 하지만, 별도로 도메인을 보유하지 않은 경우에도, AWS에서 제공해주는 기본 도메인을 사용할 수 있습니다.

이번에는 도메인 없이 CloudFront를 생성하는 방법을 알아보겠습니다.

terraform/s3/art-id/id_apnortheast2/contents-devart_without_domain.tf
# S3 Bucket for storing contents
resource "aws_s3_bucket" "contents_devart" {
  bucket = "${var.account_namespace}-contents-${var.shard_id}"
}

resource "aws_s3_bucket_public_access_block" "contents_devart" {
  bucket = aws_s3_bucket.contents_devart.id

  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

resource "aws_s3_bucket_cors_configuration" "contents_devart" {
  bucket = aws_s3_bucket.contents_devart.id

  cors_rule {
    allowed_headers = ["*"]
    allowed_methods = ["GET", "HEAD"]
    allowed_origins = ["*"]
    expose_headers  = ["ETag"]
    max_age_seconds = 3000
  }
}

resource "aws_s3_bucket_versioning" "contents_devart" {
  bucket = aws_s3_bucket.contents_devart.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_accelerate_configuration" "contents_devart" {
  bucket = aws_s3_bucket.contents_devart.id
  status = "Enabled"
}

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

data "aws_iam_policy_document" "contents_devart" {
  statement {
    principals {
      type        = "Service"
      identifiers = ["cloudfront.amazonaws.com"]
    }

    condition {
      test     = "StringEquals"
      variable = "AWS:SourceArn"
      values = [
        aws_cloudfront_distribution.devart_cdn_distribution.arn,
      ]
    }

    actions   = ["s3:GetObject"]
    resources = ["${aws_s3_bucket.contents_devart.arn}/*"]
  }
}

resource "aws_s3_bucket_lifecycle_configuration" "contents_devart" {
  bucket = aws_s3_bucket.contents_devart.id

  rule {
    id     = "contents_devart_rule"
    status = "Enabled"

    transition {
      days          = 30
      storage_class = "STANDARD_IA"
    }
  }
}

resource "aws_cloudfront_origin_access_control" "devart_contents" {
  name                              = "devart-contents"
  origin_access_control_origin_type = "s3"
  signing_behavior                  = "always"
  signing_protocol                  = "sigv4"
}

# Cloudfront Distribution
resource "aws_cloudfront_distribution" "devart_cdn_distribution" {
  origin {
    domain_name              = aws_s3_bucket.contents_devart.bucket_regional_domain_name
    origin_id                = "devart_origin"
    origin_access_control_id = aws_cloudfront_origin_access_control.devart_contents.id
  }

  enabled         = true
  is_ipv6_enabled = true
  comment         = "Cloudfront configuration for cdn"
  http_version    = "http2and3"

  # Default Cache behavior 
  default_cache_behavior {
    allowed_methods  = ["GET", "HEAD", "OPTIONS"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = "devart_origin"
    compress         = true

    forwarded_values {
      query_string = false

      cookies {
        forward = "all"
      }
    }

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

  viewer_certificate {
    cloudfront_default_certificate = true
  }

  # List of Custom Cache behavior
  # This behavior will be applied before default
  ordered_cache_behavior {

    path_pattern = "*.gif"

    allowed_methods  = ["GET", "HEAD"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = "devart_origin"
    compress         = false

    viewer_protocol_policy = "redirect-to-https"
    min_ttl                = 0
    default_ttl            = 3600
    max_ttl                = 3600

    forwarded_values {
      query_string            = true
      query_string_cache_keys = ["d"]

      cookies {
        forward = "all"
      }
    }
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  # You can set custom error response 
  custom_error_response {
    error_caching_min_ttl = 5
    error_code            = 404
    response_code         = 404
    response_page_path    = "/404.html"
  }

  custom_error_response {
    error_caching_min_ttl = 5
    error_code            = 500
    response_code         = 500
    response_page_path    = "/500.html"
  }

  custom_error_response {
    error_caching_min_ttl = 5
    error_code            = 502
    response_code         = 502
    response_page_path    = "/500.html"
  }

  # Tags of cloudfront
  tags = {
    Name = "cdn-contents without domain"
  }
}

생성된 CloudFront 테스트

  • S3 버킷에 다음과 같은 샘플 html 파일을 올려서 테스트합니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>DevOpsArt 소개</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f0f0f0;
        }
        .container {
            max-width: 800px;
            margin: auto;
            background: white;
            padding: 20px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        }
        h1 {
            text-align: center;
        }
        .video-container {
            text-align: center;
            margin-top: 20px;
        }
        iframe {
            width: 100%;
            height: 450px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>DevOpsArt 소개</h1>
        <p>DevOpsArt는 DevOps와 관련된 최신 기술과 트렌드를 다루는 전문적인 블로그 및 커뮤니티입니다. 우리는 DevOps의 개념, 도구, 그리고 최적의 실천 방법을 공유하며, 엔지니어들이 효과적이고 효율적으로 업무를 수행할 수 있도록 돕습니다.</p>
        <p>DevOpsArt의 목표는 DevOps 문화를 전파하고, 이를 통해 조직의 개발 속도와 품질을 높이는 것입니다. 우리는 다양한 튜토리얼, 가이드, 그리고 사례 연구를 제공하여, 모든 수준의 기술자들이 DevOps에 대해 이해하고 활용할 수 있도록 지원합니다.</p>
        <div class="video-container">
            <h2>유튜브 채널</h2>
            <iframe src="https://www.youtube.com/embed/vOhNCakx3kk" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
        </div>
    </div>
</body>
</html>

위 코드를 sample.html 로 저장한 후, 본인이 만든 버킷에 업로드 합니다.

업로드가 완료되면, 앞서 생성한 CloudFront 도메인을 통해 접속하실 수 있습니다. 도메인 뒤 경로에 파일명을 넣으시면 접속 가능합니다.

https://dafbqt2yr09tj.cloudfront.net/sample.html

Last updated

Was this helpful?