LoginSignup
0
0

CloudFront + S3を使ってクローズしたサイトへのアクセスを他サイトにリダイレクトする

Posted at

概要

「クローズ済みのサイトAへのアクセスを、稼働中のサイトBにリダイレクトする」
という機能を、AWSを使って以下を実装したのでその手順を記載します。

目的

閉鎖済みのサイトclosed.jpへの全てのアクセスをrunning.jpにリダイレクトする。
※ ドメイン名は適当です。

条件

  • closed.jpはドメインだけ取得している状態
  • closed.jpのサーバは破棄済みで、アクセスするとブラウザデフォルトのエラー画面が表示される
  • HTTPSの通信もリダイレクトする

構成

利用するAWSサービスとしては以下

  • Route53  
    • closed.jpへのアクセスを受け付けて、CloudFrontに流す
  • ACM
    • HTTPS通信をするための証明書を発行する
  • CloudFront
    • ClooudFront Functionを使って、ユーザアクセスを全てrunning.jpにリダイレクトする
  • S3
    • CloudFrontのオリジン、ユーザアクセスはS3到達前にリダイレクトされるため中身は空

構成図のイメージは以下
スクリーンショット 2024-04-21 22.41.32.png

リダイレクトのイメージ

以下の感じでリダイレクトされる
スクリーンショット 2024-04-21 23.00.52.png

構築

Terraformで各構成を作っていく

構築順は、ざっくりと「Route53 -> ACM -> S3 -> CloudFront」だと思う
ただしリソース同士で依存しているので、一部リソースの構ƒ築順は前後する

Route53


# ホストゾーン作成
resource "aws_route53_zone" "main" {
  name = var.domain-name  # domain-nameはclosed.jp
}

# closed.jpのアクセスをcloudfrontに向けるAレコード
resource "aws_route53_record" "main" {
  name    = var.domain-name
  type    = "A"
  zone_id = aws_route53_zone.main.zone_id

  alias {
    name                   = aws_cloudfront_distribution.main.domain_name
    zone_id                = aws_cloudfront_distribution.main.hosted_zone_id
  }
}


ACM


# us-east-1のプロバイダを作る(CloudFrontに当てる証明書はus-east-1に当てなければいけないので)
provider "aws" {
alias   = "virginia"
region  = "us-east-1"
}


# closed.jpの証明書発行
resource "aws_acm_certificate" "main" {
domain_name = "*.${var.domain-name}"

subject_alternative_names = [var.domain-name]

validation_method = "DNS"

provider = aws.virginia 
}


# 発行した証明書のドメイン所有権を確認するためのCNAMEレコードをRoute53に登録する
resource "aws_route53_record" "acm-txt" {
for_each = {
  for dvo in aws_acm_certificate.main.domain_validation_options : dvo.domain_name => {
    name   = dvo.resource_record_name
    record = dvo.resource_record_value
    type   = dvo.resource_record_type
  }
}

allow_overwrite = true
name            = each.value.name
records         = [each.value.record]
ttl             = 60
type            = each.value.type
zone_id         = aws_route53_zone.main.zone_id
}

S3

# バケットを作る
resource "aws_s3_bucket" "main" {
  bucket = "my_bucket"
}

# CloudFrontからS3にアクセスするためのポリシーを作る
# ※ 今回の構成だとCloudFrontからS3にアクセスが行かないので不要かと思うが念のため
data "aws_iam_policy_document" "main-policy" {
  statement {
    actions   = ["s3:GetObject"]
    resources = ["${aws_s3_bucket.main.arn}/*"]

    principals {
      identifiers = ["cloudfront.amazonaws.com"]
      type        = "Service"
    }

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

# 作ったポリシーをバケットにアタッチする
resource "aws_s3_bucket_policy" "main-bucket-policy" {
  bucket = aws_s3_bucket.main.id
  policy = data.aws_iam_policy_document.main-policy.json
}

CloudFront

# 外部リソース(キャッシュポリシー)を取得
data "aws_cloudfront_cache_policy" "enable-cache" {
  name = "Managed-CachingOptimized"
}

#  CloudFront Functionを指定のソースから読み込み
resource "aws_cloudfront_function" "all_redirect" {
  name    = "all-redirect"
  runtime = "cloudfront-js-1.0"
  code    = file("./src/redirect.js")
}

# CloudFront作成
resource "aws_cloudfront_distribution" "main" {
  enabled             = true
  aliases             = "closed.jp"
  default_root_object = "index.html"

  # オリジンとしてS3を宣言
  origin {
    domain_name              = aws_s3_bucket.main.bucket_regional_domain_name
    origin_id                = aws_s3_bucket.main.bucket
    origin_access_control_id = aws_cloudfront_origin_access_control.main.id
  }
  
  default_cache_behavior {
    allowed_methods        = ["GET", "HEAD"]
    cached_methods         = ["GET", "HEAD"]
    # デフォルトのビヘイビアのオリジンをS3にする
    target_origin_id       = aws_s3_bucket.main.bucket
    viewer_protocol_policy = "redirect-to-https"
    cache_policy_id        = data.aws_cloudfront_cache_policy.enable-cache.id

    # デフォルトビヘイビアにリダイレクト用のCloudFrontFunctionを設定
    function_association {
      # viewer requestなのでオリジンへのアクセス前に実行される
      event_type   = "viewer-request"
      function_arn = aws_cloudfront_function.all_redirect.arn
    }
  }

  # アクセス制限は特に設けない
  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  # ACMの証明書を当てる
  viewer_certificate {
    acm_certificate_arn            = aws_acm_certificate.main.arn
    minimum_protocol_version       = "TLSv1.2_2021"
    ssl_support_method             = "sni-only"

  }


}

# CloudFrontがs3にアクセスするためのOAC
resource "aws_cloudfront_origin_access_control" "main" {
  name                              = "s3"
  description                       = "s3"
  origin_access_control_origin_type = "s3"
  signing_behavior                  = "always"
  signing_protocol                  = "sigv4"
}

CloudFront Function

// 全てのアクセスをrunning.jpにリダイレクトする。
function handler() { 
    return {
            statusCode: 301,
            statusDescription: 'Moved Permanently',
            headers:
                { "location": { "value": `https://running.jp` } }
        };

}

DNS権限委任

AWS側の準備は前述の通りだが、これだけだとclosed.jpの名前解決を行う際にRoute53が経路に入らないためAWSにアクセスが来ない

そのためclosed.jpを管理しているDNSに、当該ドメインの権限をRoute53側に委任してもらうよう、設定を施す必要がある

権限委任の設定方法は使っているDNSのサービスによって異なるが、基本的にはRoute53のホストゾーン作成時に発行されるNSレコードをDNSに設定することになるはず。

例えばお名前comだと以下記事の手順になる。
https://dev.classmethod.jp/articles/route53-domain-onamae/

感想

AWSを使ってリダイレクトする方法は沢山ある。

例えば下記が思いつく
・S3の静的ホスティング機能
・ELBのリスナールール
・EC2 / ECSにWebサーバを立ててそこでやる
・Lambda
・WAF

ただ、CloudFront+S3以外の機能だと、固定費がかかるケースが多いため
安さの観点だと今回の方法が良いと思う。

また、S3の静的ホスティング機能を使ってリダイレクトさせる方法も
今回の方法と手間・料金がほぼ変わらないのでそちらでも良いと思う
※ むしろ高アクセスの場合はそっちの方が安いかも

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0