Давайте рассмотрим архитектуру, которую мы собрали в Части 1.

Ознакомьтесь с частью 1
- основной веб-сайт, размещенный на www. субдомене
- приложение html / js / css, размещенное в корзине S3
- облачный дистрибутив для предоставления нам https URL
- сертификат, который будет использоваться с облачным распределением для этого домена
- серию небольших URL, которые будут перенаправлять на основной веб-сайт

Давайте начнем строить терраформу

создайте каталог вашего проекта

  • вам нужен main.tf для хранения всех ваших ресурсов
  • вам нужен файл variables.tf для хранения ваших входных данных в вашей инфраструктуре.
  • вам нужен файл var для хранения значений ваших входных данных для вашей инфраструктуры

создайте свои исходные файлы tf

Основной веб-сайт, который мы хотим создать, - www.example.com.

resource "aws_s3_bucket" "logs" {
  bucket = "${var.site_name}-site-logs"
  acl = "log-delivery-write"
}
resource "aws_s3_bucket" "www_site" {
  bucket = "www.${var.site_name}"
  logging {
    target_bucket = "${aws_s3_bucket.logs.bucket}"
    target_prefix = "www.${var.site_name}/"
  }
  website {
    index_document = "index.html"
  }
}

variables.tf

variable "site_name" {
  description = "My site"
}

вар-файлы / my-site.tf

site_name = "mysite.com"

Я считаю, что лучше всего мы учимся, когда видим, как все ломается! И здесь есть возможность что-то сломать.

Зачем помещать журналы доступа в отдельную корзину?

Давайте упростим задачу, поместив журналы доступа в ту же корзину, что и веб-сайт. Зачем мне 2 ведра?

resource "aws_s3_bucket" "www_site" {
  bucket = "www.${var.site_name}"
  logging {
    target_bucket = "www.${var.site_name}"
  }
  website {
    index_document = "index.html"
  }
}

Спланируйте и примените свой терраформ, а затем посетите свой веб-сайт напрямую через URL-адрес веб-сайта S3. Обновите страницу несколько раз, а затем посмотрите содержимое корзины S3.

  • Ваши журналы доступа теперь также общедоступны, потому что к ним можно получить доступ через URL-адрес вашего веб-сайта.
  • В ваших журналах доступа длинные и непонятные имена файлов, и они засоряют ваш каталог. Если вы выполняете развертывание с использованием aws s3 sync в своем сегменте, вам придется удалять журналы доступа каждый раз при развертывании.
  • Подождите 10 минут и просмотрите активность в журналах доступа. Вы заметите, что в процессе создания файла, содержащего ваши журналы доступа, будет создан журнал доступа к процессу создания файла, содержащего ваши журналы доступа и т. Д., Т. Д. И т. Д.

Я делал это раньше. Я был так сбит с толку. Используйте отдельное ведро.

Создайте свой сертификат

Нам нужен сертификат, который мы можем получить бесплатно через ACM, но есть одна загвоздка.

resource "aws_acm_certificate" "cert" {
  domain = "www.example.com"
}

Применение этого ресурса terraform начнет процесс запроса сертификата, но сертификат необходимо утвердить и создать вне канала. Есть два способа справиться с этим сценарием

  • Не управляйте сертификатом с помощью terraform. Создайте его вручную и перетащите ARN сертификата везде, где вам нужно его использовать.
  • Управляйте сертификатом с помощью terraform, но создайте его вручную, а затем используйте terraform import для импорта ресурса ПОСЛЕ его утверждения и создания.

Теперь мы можем создать дистрибутив Cloudfront и завершить соединение частей вместе:

resource "aws_cloudfront_origin_access_identity" "origin_access_identity" {
  comment = "cloudfront origin access identity"
}
resource "aws_cloudfront_distribution" "website_cdn" {
  enabled      = true
  price_class  = "PriceClass_200"
  http_version = "http1.1"
  aliases = ["www.${var.site_name}"]
  origin {
    origin_id   = "origin-bucket-${aws_s3_bucket.www_site.id}"
    domain_name = "www.${var.site_name}.s3.us-east-2.amazonaws.com"
    s3_origin_config {
      origin_access_identity = "${aws_cloudfront_origin_access_identity.origin_access_identity.cloudfront_access_identity_path}"
    }
  }
  default_root_object = "index.html"
  default_cache_behavior {
    allowed_methods = ["GET", "HEAD"]
    cached_methods  = ["GET", "HEAD"]
    target_origin_id = "origin-bucket-${aws_s3_bucket.www_site.id}"
    min_ttl          = "0"
    default_ttl      = "300"                                              //3600
    max_ttl          = "1200"                                             //86400
    // This redirects any HTTP request to HTTPS. Security first!
    viewer_protocol_policy = "redirect-to-https"
    compress               = true
    forwarded_values {
      query_string = false
      cookies {
        forward = "none"
      }
    }
  }
  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }
  viewer_certificate {
    acm_certificate_arn      = "${aws_acm_certificate.cert.arn}"
    ssl_support_method       = "sni-only"
  }
}

Здесь несколько важных пунктов

  • aws_cloudfront_origin_access_identity создаст это для вас в терраформе и будет управлять им. Вы можете либо создать и совместно использовать удостоверение доступа к источнику для нескольких распределений, либо использовать одно удостоверение доступа к источнику для каждого распределения.
  • Политика протокола просмотра redirect-http-to-https для обеспечения https соблюдения посетителей сайта

Заблокируйте ковш S3

Политика корзины позволяет нам определять безопасность корзины. В этом сценарии мы можем сохранить сегмент приватным и доступным только для Cloudfront с помощью Origin Access Identity. Мы можем выразить это в политике корзины:

main.tf

data "template_file" "bucket_policy" {
  template = "${file("bucket_policy.json")}
  vars {
    origin_access_identity_arn = "${aws_cloudfront_origin_access_identity.origin_access_identity.cloudfront_access_identity_path}"
    bucket = "${aws_s3_bucket.www_site.arn}"
  }
}
resource "aws_s3_bucket" "www_site" {
  bucket = "www.${var.site_name}"
  policy = "${data.template_file.bucket_policy.rendered}"
  ...
}

bucket_policy.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "OnlyCloudfrontReadAccess",
      "Principal": {
        "AWS": "${origin_access_identity_arn}"
      },
      "Effect": "Allow",
      "Action": [
        "s3:GetObject"
      ],
      "Resource": "arn:aws:s3:::${bucket}/*"
    }
  ]
}

Создайте запись DNS

main.tf

resource "aws_route53_record" "www_site" {
  zone_id = "${data.aws_route53_zone.site.zone_id}"
  name = "www.${var.site_name}"
  type = "A"
  alias {
    name = "${aws_cloudfront_distribution.website_cdn.domain_name}"
    zone_id  = "${aws_cloudfront_distribution.website_cdn.hosted_zone_id}"
    evaluate_target_health = false
  }
}

Примените свой терраформ и проверьте его.

Написание автоматических тестов для вашей инфраструктуры

Как и в любом проекте программирования, вы хотите убедиться, что у вас есть тесты для вашего кода. Но мы пишем terraform, а для terraform нет тестового раннера, или есть?

Все, что нам нужно для тестирования нашей терраформы, - это любой язык, который позволяет нам писать веб-запросы. Мы создадим 2 набора тестов, чтобы убедиться, что на mysite.com все работает.

Создайте тесты для проверки конфигурации вашего сегмента

s3_bucket_spec.rb

require 'serverspec'
context 's3 bucket' do
  describe command('aws s3 ls s3://dperez-test-bucket') do
    its(:stdout) { should_match /Access Denied/ }
  end
  describe command('curl -i https://s3.amazonaws.com/dperez-test-bucket') do
    its(:stdout) { should_match /Access Denied/ }
  end
end
context 'cloudfront' do
  describe command('curl -i https://www.mysite.com') do
    its(:stdout) { should_match /200 OK/ }
  end
  describe command('curl -i http://www.mysite.com') do
    its(:stdout) { should_match /301 Redirect/ }
  end
end

Запустите тесты с помощью rspec, чтобы проверить только что созданную инфраструктуру.

Если вам понравилась статья, посетите мой сайт www.intricatecloud.io или подпишитесь на мой список рассылки здесь, чтобы узнать больше о различных типах приложений, созданных на AWS.