Перенаправление запросов с 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
Весь код тут