ディップ Advent Calendar 2019 の24日目の記事となります。
今年は3つのAdvent Calendarを別々の場所書いておりその最後になります。
1つ目2つ目はこちら
2つとも技術系というよりはマネジメント系によってしまったので最後ぐらいは軽く技術に触れようと本タイトルでの記事投稿をさせていただきました。
現在ディップSREチームではインフラ構成管理にTerrafromの導入をはじめております。
サービスが多くあることから全体のベストプラクティスのTerraform設計から考え、新規サービスや機能などのインフラ構成をTerraform化させやっとはじめの1歩を歩んだ状態です。
環境分割の部分については同じくSREチームの @hayaosato が環境分割について触れていますのでよければご覧ください。
さて、今回行いたいこととしてはCloudFront+ALB+S3でリダイレクト+静的サイトホスティングする環境を作ることです。
CloudFrontでは特定のURLパス(aaa/ bbb/ ccc/ )の時はS3コンテンツを見せ、それ以外はALBに振り、ALBに来たアクセスは別ドメインにリダイレクトするという設定を行なっております。
今回はこの中の以下の部分をTerraform化しました。
コンテンツ用のディレクトリは、destroyしてしまうとコンテンツの中身自体が消えてしまうためterraformでの推奨はされていないという記事もあったためこちらは手動での作成を行なっております。
また、CFやRoute53については諸々の理由で既存で存在していたためこちらも対象外にしてあります。
実際のコードTreeとコードはこんな感じ
[AWSアカウント名]/
└──[環境名]
└── [サービス名]
└── [機能名]
├── alb.tf
├── cloudfront.tf
├── main.tf
├── provider.tf
└── s3.tf
// CloudFrontアクセスログ用バケット作成
resource "aws_s3_bucket" "cf-accesslog-hogehoge-proxy" {
bucket = var.s3bucket_cf_accesslog
acl = "private"
tags = {
create_type = "terraform"
}
}
resource "aws_s3_bucket_public_access_block" "cf-accesslog-hogehoge-proxy" {
bucket = "${aws_s3_bucket.cf-accesslog-hogehoge-proxy.id}"
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
// S3アクセスログ用バケット作成
resource "aws_s3_bucket" "s3-accesslog-baito-app-proxy" {
bucket = var.s3bucket_cf_accesslog
acl = "private"
tags = {
create_type = "terraform"
}
}
resource "aws_s3_bucket_public_access_block" "s3-accesslog-hogehoge-proxy" {
bucket = "${aws_s3_bucket.s3-accesslog-hogehoge-proxy.id}"
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_lb" "hogehoge_rd" {
name = var.hogehoge_rd
load_balancer_type = "application"
security_groups = ["sg-aaaa", "sg-bbbb"]
subnets = ["subnet-cccc", "subnet-dddd"]
enable_deletion_protection = false
enable_http2 = true
idle_timeout = "60"
internal = false
ip_address_type = "ipv4"
tags = {
create_type = "terraform"
}
}
resource "aws_lb_target_group" "hogehoge_rd" {
name = var.hogehoge_rd
port = "80"
protocol = "HTTP"
slow_start = "0"
deregistration_delay = "300"
vpc_id = "vpc-eeee"
tags = {
create_type = "terraform"
}
health_check {
enabled = true
healthy_threshold = "5"
interval = "30"
matcher = "200"
path = "/"
port = "traffic-port"
protocol = "HTTP"
timeout = "5"
unhealthy_threshold = "2"
}
}
resource "aws_lb_listener" "hogehoge_proxy_80" {
load_balancer_arn = "${aws_lb.hogehoge_rd.arn}"
port = "80"
protocol = "HTTP"
default_action {
type = "redirect"
order = "1"
redirect {
host = "#{host}"
path = "/#{path}"
port = "443"
protocol = "HTTPS"
query = "#{query}"
status_code = "HTTP_301"
}
}
}
resource "aws_lb_listener" "hogehoge_proxy_443" {
load_balancer_arn = "${aws_lb.hogehoge_rd.arn}"
port = "443"
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-2016-08"
certificate_arn = "arn:aws:acm:ap-northeast-1:fffff:certificate/ggggg"
default_action {
order = "1"
target_group_arn = "${aws_lb_target_group.hogehoge_rd.arn}"
type = "forward"
}
}
resource "aws_lb_listener_rule" "hogehoge_proxy_443" {
listener_arn = "${aws_lb_listener.hogehoge_proxy_443.arn}"
priority = "1"
action {
order = "1"
redirect {
host = var.redirect_host
path = "/#{path}"
port = "443"
protocol = "HTTPS"
query = "#{query}"
status_code = "HTTP_301"
}
type = "redirect"
}
condition {
path_pattern {
values = ["*"]
}
}
}
resource "aws_cloudfront_distribution" "hogehoge_com" {
aliases = ["hogehoge.com"]
default_cache_behavior {
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
compress = true
default_ttl = "86400"
forwarded_values {
cookies {
forward = "none"
}
headers = ["*"]
query_string = true
}
max_ttl = "31536000"
min_ttl = "0"
smooth_streaming = false
target_origin_id = "${var.target_origin_id_ELB}/*"
viewer_protocol_policy = "redirect-to-https"
}
enabled = true
http_version = "http2"
is_ipv6_enabled = true
logging_config {
bucket = var.s3_contents_domain
include_cookies = false
}
ordered_cache_behavior {
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
compress = false
default_ttl = "86400"
forwarded_values {
cookies {
forward = "none"
}
query_string = false
}
max_ttl = "31536000"
min_ttl = "0"
path_pattern = "/aaa/"
smooth_streaming = false
target_origin_id = var.target_origin_id_S3
viewer_protocol_policy = "redirect-to-https"
}
ordered_cache_behavior {
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
compress = false
default_ttl = "86400"
forwarded_values {
cookies {
forward = "none"
}
query_string = false
}
max_ttl = "31536000"
min_ttl = "0"
path_pattern = "/bbb/"
smooth_streaming = false
target_origin_id = var.target_origin_id_S3
viewer_protocol_policy = "redirect-to-https"
}
ordered_cache_behavior {
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
compress = false
default_ttl = "86400"
forwarded_values {
cookies {
forward = "none"
}
query_string = false
}
max_ttl = "31536000"
min_ttl = "0"
path_pattern = "/ccc/"
smooth_streaming = false
target_origin_id = var.target_origin_id_S3
viewer_protocol_policy = "redirect-to-https"
}
origin {
custom_origin_config {
http_port = "80"
https_port = "443"
origin_keepalive_timeout = "5"
origin_protocol_policy = "match-viewer"
origin_read_timeout = "30"
origin_ssl_protocols = ["TLSv1", "TLSv1.1", "TLSv1.2"]
}
domain_name = var.elb_domain
origin_id = "${var.target_origin_id_ELB}/*"
origin {
domain_name = var.s3_contents_domain
origin_id = var.target_origin_id_S3
s3_origin_config {
origin_access_identity = "origin-access-identity/cloudfront/${var.cloudfront_id}"
}
}
price_class = "PriceClass_All"
restrictions {
geo_restriction {
restriction_type = "none"
}
}
retain_on_delete = false
tags = {
create_type = "terraform"
}
viewer_certificate {
acm_certificate_arn = var.hogehoge_acm_certificate_arn
cloudfront_default_certificate = false
minimum_protocol_version = "TLSv1.1_2016"
ssl_support_method = "sni-only"
}
wait_for_deployment = true
}
今回、vars部分は省略しますが、無事作成することができました。
また、社内ではTerraform導入の先駆者がいないためtfファイルの作成は初めは苦労してしまいます。
その中で私自身が行なっている作成方法を紹介したいと思います。
- 手動でAWS上に構築
- まずはコンソール上で触れてみる、大事。
- 1で作ったものをterraformer import でリソースを取得
- terraform import だとstateファイルから追わないといけないので初心者には厳しい
- default設定で不要なもの、空情報がそのまま取得され通らないものを除去しTerraform実行できるように修正
- terraformerが独自の書き方などをしているところもあるのでimportをしてもそのままapplyできない場合が多い、あとバージョンの違いあくまでも1参考として活用する
- deployして問題ないか確認
- 1回では通らないことが多い
- 他環境へのdeployのことも考えvariableで変数化して再度deployし差分がないか確認
- ここでまた名前とか変えたくなって苦労する
実際まだ現在進行形でtfファイルの整備を進めておりますが、細かいところまで手が回っておらずtfファイルについては参考にならない部分が多いかもしれません。
とはいえこれからもAWSのリソース作成はTerraformを軸に進めていこうという状況なので、おそらくこの記事は今年中にもう少しアップデートさせていきます。
ということで、皆さま良いクリスマスイブをお過ごしください。