Terraform. Перенаправление запросов с S3 хостинга сайта на другой домен

Автор: Admin | 01.02.2018

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *