
Перенаправление запросов с S3 хостинга сайта через CloudFront CDN на другой домен и отлитие этого в конфиге Terraform
Задача
1. Необходимо разместить файл на новом домене и отдавать через CloudFront CDN по HTTPS.
2. Все остальные запросы перенапрвлять на основной домен.
Поведение должно быть следующим:
В бакете на S3 располагается один файл target.file
Запрос my.cdn.domain/target.file должен отдавать target.file
Запрос my.cdn.domain должен редиректить на my.rdr.domain
Любой другой запрос к домену будет отдавать 404, который так же надо перенаправить в корень my.rdr.domain
Файлов может быть любое количество, они так же будут отдаваться по прямому запросу к ним
Теория
1. Создать бакет. Указать Static website hosting в Properties. Прописать Index и Error document, создать их и в их Metadata сделать редирект на нужный домен.
2. Создать CDN. Вписать Endpoint из S3 Static website hosting в CloudFront/Origins/Origin Domain Name. Указать в алиасе my.cdn.domain.
3. Подождать, поскольку CDN создается или изменяется около 20 минут.
Отлитие в Terraform'е
Приведу только код для задачи
Переменные в vars.tf, где понятно что есть что:
variable "main" {
type = "map"
default {
bucket_name = "my-bucket"
cdn_domain = "my.cdn.domain"
rdr_domain = "my.rdr.domain"
}
}
Основной код в main.tf:
### Анонсировать сертификат для my.cdn.domain
# Который должен быть создан заранее. Смотри примечание снизу
data "aws_acm_certificate" "my_certificate" {
domain = "${var.main["cdn_domain"]}"
statuses = ["ISSUED"]
}
### Создать бакет для my.cdn.domain
resource "aws_s3_bucket" "my_bucket" {
bucket = "${var.main["bucket_name"]}"
acl = "private"
region = "${var.region}"
tags {
Name = "${var.main["bucket_name"]}"
}
# Полиси для бакета. Чтение для всех
policy = <<EOF
{
"Id": "Policy1516899566603",
"Version": "2012-10-17",
"Statement": [{
"Sid": "Stmt1516899563175",
"Action": "s3:GetObject",
"Effect": "Allow",
"Resource": "arn:aws:s3:::${var.main["bucket_name"]}/*",
"Principal": "*"
}]
}
EOF
# Объявить бакета как Static website hosting
website {
index_document = "index.html"
error_document = "error.html"
}
}
# Создать индекс файл и редирект на my.rdr.domain
resource "aws_s3_bucket_object" "index_file" {
bucket = "${aws_s3_bucket.my_bucket.id}"
acl = "private"
source = "/dev/null"
key = "index.html"
content_type = "text/html"
website_redirect = "${var.main["rdr_domain"]}"
}
# Создать 404 файл и редирект на my.rdr.domain
resource "aws_s3_bucket_object" "error_file" {
bucket = "${aws_s3_bucket.my_bucket.id}"
acl = "private"
source = "/dev/null"
key = "error.html"
content_type = "text/html"
website_redirect = "${var.main["rdr_domain"]}"
}
# Создать контент файл
resource "aws_s3_bucket_object" "target_file" {
bucket = "${aws_s3_bucket.my_bucket.id}"
acl = "private"
source = "files/target.file"
key = "target.file"
content_type = "text/html"
}
### Создать CDN
resource "aws_cloudfront_distribution" "my_cdn" {
origin {
domain_name = "${aws_s3_bucket.my_bucket.website_endpoint}"
origin_id = "CDN for ${var.main["bucket_name"]}"
custom_origin_config {
origin_protocol_policy = "http-only"
http_port = "80"
https_port = "443"
origin_ssl_protocols = ["TLSv1.1"]
}
}
enabled = true
is_ipv6_enabled = true
comment = "CDN for ${var.main["cdn_domain"]}"
aliases = ["${var.main["cdn_domain"]}"]
default_cache_behavior {
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "${var.main["bucket_name"]}"
compress = "True"
min_ttl = 0
default_ttl = 86400
max_ttl = 31536000
viewer_protocol_policy = "redirect-to-https"
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
}
price_class = "PriceClass_All"
viewer_certificate {
cloudfront_default_certificate = "false"
acm_certificate_arn = "${data.aws_acm_certificate.my_certificate.arn}"
minimum_protocol_version = "TLSv1.1_2016"
ssl_support_method = "sni-only"
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
}
### Создать my.cdn.domain зону
resource "aws_route53_zone" "my_dns_zone" {
name = "${var.main["cdn_domain"]}"
}
# Создать алиас для домена my.cdn.domain
# Ведущий на CDN
resource "aws_route53_record" "my_domain" {
zone_id = "${aws_route53_zone.my_dns_zone.zone_id}"
name = "${var.main["cdn_domain"]}"
type = "A"
alias {
name = "${aws_cloudfront_distribution.my_cdn.domain_name}"
zone_id = "${aws_cloudfront_distribution.my_cdn.hosted_zone_id}"
evaluate_target_health = false
}
}
Примечание: cертификат для домена невозможно создать при помощи терраформа, поскольку надо подтверждать владение доменом. Поэтому его надо создать руками из веб морды амазона. В данном конфиге он не создается, а только анонсируется для дальнейшего использования в CDN. Так же, в целях тестирования имеет смысл параметры default_ttl и max_ttl ставить в 0. Как видно из кода, target файл должен лежать по пути files/target.file
Весь код тут