概要
「クローズ済みのサイト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到達前にリダイレクトされるため中身は空
リダイレクトのイメージ
構築
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の静的ホスティング機能を使ってリダイレクトさせる方法も
今回の方法と手間・料金がほぼ変わらないのでそちらでも良いと思う
※ むしろ高アクセスの場合はそっちの方が安いかも