あめがえるのITブログ

頑張りすぎない。ほどほどに頑張るブログ。

Amazon CloudFront+S3のWebサイトでOAIで送信元アクセス制御してみた

Amazon CloudFront+S3の構成で直接S3にアクセスさせたくないので、OAI(オリジンアクセスアイデンティティ)を設定してCloudFrontからの接続以外は受け付けないようにする。

Amazon CloudFrontとは

高いパフォーマンス、セキュリティ、デベロッパーの利便性のために構築されたコンテンツ配信ネットワーク(CDN)サービス。
aws.amazon.com

OAIとは

CloudFrontの分散恩典つを取得するためにS3バケットにアクセス際に使用される特殊なユーザー。

OAIとOACの違い

OAC(オリジンアクセスコントロール):細かなポリシー設定やAWS Signature Version 4(SigV4)を必要とするAWSリージョンでのPOSTメソッドを使用したHTTPおよびHTTPSリクエスト、SSE-KMSとの連携する場合に使用する。
aws.amazon.com



やること

terraformでCloudFrontとS3の静的Webサイトを作成し、CloudFrontのURLへ接続し接続ができ、S3のURLへ接続し接続できないことの確認する。

環境

※下記を作成

実践!

1.表示用htmlファイル作成

# vi index.html
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Welcome to My Static Site</title>
</head>
<body>
    <h1>Welcome to My Static Site</h1>
    <p>This is the main page.</p>
</body>
</html>


2.エラー用htmlファイル作成

# vi error.html
<!-- error.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Error Page</title>
</head>
<body>
    <h1>Oops! Something went wrong.</h1>
    <p>We couldn't find the page you were looking for.</p>
</body>
</html>


3.環境構築

# vi main.html
provider "aws" {
  region  = "ap-northeast-1"
  profile = "testvault"
}

resource "aws_s3_bucket" "static_website" {
  bucket = "my-static-website-bucket123456789000"
}

## パブリックアクセスブロックは検証のためオフにする。
resource "aws_s3_bucket_public_access_block" "static_website" {
  bucket                  = aws_s3_bucket.static_website.id
  block_public_acls       = false
  block_public_policy     = false
  ignore_public_acls      = false
  restrict_public_buckets = false
}

resource "aws_s3_bucket_website_configuration" "website_config" {
  bucket = aws_s3_bucket.static_website.id
  
  index_document {
    suffix = "index.html"
  }

  error_document {
    key = "error.html"
  }
}

resource "aws_s3_object" "website_index" {
  bucket = aws_s3_bucket.static_website.bucket
  key    = "index.html"
  content_type = "text/html"
  source       = "index.html"
}

resource "aws_s3_object" "website_error" {
  bucket = aws_s3_bucket.static_website.bucket
  key    = "error.html"
  content_type = "text/html"
  source       = "error.html"
}

## OAIを設定
resource "aws_cloudfront_origin_access_identity" "oai" {
  comment = "OAI for my-static-website-bucket"
}

resource "aws_cloudfront_distribution" "s3_distribution" {
  origin {
    domain_name = aws_s3_bucket.static_website.bucket_regional_domain_name
    origin_id   = "S3Origin"

    ## CloudFrontにOAIを設定
    s3_origin_config {
      origin_access_identity = aws_cloudfront_origin_access_identity.oai.cloudfront_access_identity_path
    }
  }

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

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

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

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

  viewer_certificate {
    cloudfront_default_certificate = true
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }
}

# S3 Bucket Policy
resource "aws_s3_bucket_policy" "bucket_policy" {
  bucket = aws_s3_bucket.static_website.id

  policy = jsonencode({
    Version   = "2012-10-17",
    Statement = [
      {
        Sid       = "AllowCloudFrontAccess"
        Effect    = "Allow"
        Principal = {
          ## OAIを使用したアクセスのみ許可
          AWS = "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${aws_cloudfront_origin_access_identity.oai.id}"
        },
        Action    = "s3:GetObject",
        Resource  = "${aws_s3_bucket.static_website.arn}/*"
      }
    ]
  })
}

※フォルダ階層は下記のように同列に置く

┬ main.tf
├ index.html
└ error.html
# terraform plan
# terraform apply

※完成!

4.接続
4-1.CloudFrontのURLへ接続
※でけた!

4-2.S3バケットへ直接接続
※NG


感想

OACもそのうちやるか( ̄д ̄)