【AWS】Terraformでアクセスを分散、WebサーバーをHTTPS化する その1(ALB) 

## 概要
TerraformでAWSサービスを使用して、

- 負荷分散
- 独自ドメインの設定
- SSL証明書を作成してHTTPS化

上記の3つを含めた構成を作成する手順をまとめました。

## 目次
1. アプリケーションロードバランサー(ALB)の作成
  - ALBの作成
  - ターゲットグループの作成 / ターゲットの登録
  - リスナーを設定
  - ALBのDNS名からHTTPアクセス確認　__←本記事はここまで__
1. Route53でDNS設定
  - ドメインの取得（例はfreenomの無料ドメイン）
  - ホストゾーンの作成
  - DNSレコードの定義
  - ネームサーバーの設定を加える
  - 取得したドメインへHTTPアクセス確認
1. AWS Certificate Manager(ACM)でSSL証明書の作成
  - SSL証明書の作成
  - SSL証明書の検証
  - HTTPSリスナーの定義
  - HTTPSアクセス確認

本記事ではアプリケーションロードバランサー(ALB)の作成までをまとめた。

## 構成図
目標構成図はこちら。
![ALB_Route53_ACM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813991/ac0da77b-d9fa-f1cc-5fd0-63f304929274.png)

## 前提環境
今回は2つのAZにパブリックサブネットを一つずつ作成し、それぞれのサブネットにEC2インスタンスを構築した状態までを準備する。
なお、インターネット接続に必要なルートテーブル、インターネットゲートウェイ、セキュリティグループも設定済み。
### 前提環境の構成図
![ALB_Route53_ACM_init.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813991/81979a80-fe85-4c69-ec52-746b39adba47.png)

下記内容で前提環境は構築可能。

```
.
├── ec2.tf
├── network.tf
├── provider.tf
└── security_group.tf
```

```terraform:provider.tf
provider "aws" {
  region = "ap-northeast-1"
}
```

```terraform:network.tf
# VPC作成
resource "aws_vpc" "vpc" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "my-vpc-001"
  }
}

#インターネットゲートウェイ
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc.id

  tags = {
    Name = "my-igw-001"
  }
}

#　サブネット
## パブリックサブネット
resource "aws_subnet" "public" {
  vpc_id                  = aws_vpc.vpc.id
  cidr_block              = "10.0.0.0/24"
  map_public_ip_on_launch = true
  availability_zone       = "ap-northeast-1a"

  tags = {
    Name = "my-public-subnet-001"
  }
}
## パブリックサブネット2
resource "aws_subnet" "public_2" {
  vpc_id                  = aws_vpc.vpc.id
  cidr_block              = "10.0.1.0/24"
  map_public_ip_on_launch = true
  availability_zone       = "ap-northeast-1c"

  tags = {
    Name = "my-public-subnet-002"
  }
}

# ルートテーブル
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.vpc.id

  tags = {
    Name = "my-public-rtb-001"
  }
}
## パブリックルートを設定
resource "aws_route" "public" {
  route_table_id         = aws_route_table.public.id
  gateway_id             = aws_internet_gateway.igw.id
  destination_cidr_block = "0.0.0.0/0"
}
## サブネット1へのルートテーブルの関連付け
resource "aws_route_table_association" "public" {
  subnet_id      = aws_subnet.public.id
  route_table_id = aws_route_table.public.id
}
## サブネット2へのルートテーブルの関連付け
resource "aws_route_table_association" "public_2" {
  subnet_id      = aws_subnet.public_2.id
  route_table_id = aws_route_table.public.id
}
```

```terraform:security_group.tf
# セキュリティグループ
resource "aws_security_group" "sg_for_ec2" {
  vpc_id = aws_vpc.vpc.id
  name   = "my-sg-001"

  tags = {
    Name = "my-sg-001"
  }
}
## HTTPインバウンドルール
resource "aws_security_group_rule" "ingress_http" {
  security_group_id = aws_security_group.sg_for_ec2.id
  type              = "ingress"
  from_port         = 80
  to_port           = 80
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
}
## アウトバウンドルール
resource "aws_security_group_rule" "egress" {
  security_group_id = aws_security_group.sg_for_ec2.id
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
}
```

```terraform:ec2.tf
# ec2(1)
resource "aws_instance" "web-server-instance" {
  ami                    = "ami-09ebacdc178ae23b7"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.public.id
  availability_zone      = "ap-northeast-1a"
  vpc_security_group_ids = [aws_security_group.sg_for_ec2.id]

  tags = {
    Name = "my-ec2-001"
  }

  # httpd　ここの中身は何でもok。2つのインスタンスの見分けをつけたいだけ
  user_data = <<EOF
      #!/bin/bash
      yum update -y
      yum install -y httpd
      systemctl start httpd
      chkconfig httpd on
      echo "<h1 style='color: indigo;'>Hi there, I'm the first EC2 instance.</h1>" > var/www/html/index.html
  EOF
}
# ec2(2)
resource "aws_instance" "web-server-instance_2" {
  ami                    = "ami-09ebacdc178ae23b7"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.public_2.id
  availability_zone      = "ap-northeast-1c"
  vpc_security_group_ids = [aws_security_group.sg_for_ec2.id]

  tags = {
    Name = "my-ec2-002"
  }

  # httpd ここの中身は何でもok。2つのインスタンスの見分けをつけたいだけ
  user_data = <<EOF
      #!/bin/bash
      yum update -y
      yum install -y httpd
      systemctl start httpd
      chkconfig httpd on
      echo "<h1 style='color: orange;'>Yo, I'm the second EC2 instance.</h1>" > var/www/html/index.html
  EOF
}
```
</div>
</details>

ちなみにそれぞれのEC2のパブリックIPにブラウザでアクセスした際の表示はこちら。
Name : my-ec2-001 (/var/www/html/index.html)
![1st.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813991/24e6c585-fce6-5ffe-0b6f-7380851351af.png)
Name : my-ec2-002 (/var/www/html/index.html)
![2nd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813991/88572b47-f6e1-6a2a-f5d1-9012f9e967e8.png)

## 1. アプリケーションロードバランサー(ALB)の作成
### ALBの作成
前提環境のtfファイルと同じディレクトリにてalb.tfを作成
下記を追記しロードバランサーリソースの構築。

```terraform:alb.tf
# ALBを作成
resource "aws_lb" "alb" {
  name               = "alb"
  load_balancer_type = "application"
  internal           = false

  subnets = [
    aws_subnet.public.id,
    aws_subnet.public_2.id,
  ]

  security_groups = [
    aws_security_group.sg_for_ec2.id
  ]
}
```
- `load_balancer_type = "application"`  
ALBを作成するためタイプにApplicationを指定。
- `internal = false`  
インターネット向けのALBのためfalseを設定。
- `subnets`  
異なるAZのサブネットを指定してクロスゾーン負荷分散を構成。

### ターゲットグループの作成 / ターゲットの登録
続いてリクエストをルーティングするターゲットグループを作成し、ターゲットを登録する。

```terraform:alb.tf
# ターゲットグループの作成
resource "aws_lb_target_group" "alb_target_group" {
  name     = "my-target-group"
  vpc_id   = aws_vpc.vpc.id
  port     = 80
  protocol = "HTTP"
}

#　ターゲットの登録
## パブリックサブネット1のEC2インスタンスをターゲットに登録
resource "aws_lb_target_group_attachment" "target" {
  target_group_arn = aws_lb_target_group.alb_target_group.arn
  target_id        = aws_instance.web-server-instance.id
  port             = 80
}
## パブリックサブネット2のEC2インスタンスをターゲットに登録
resource "aws_lb_target_group_attachment" "target_2" {
  target_group_arn = aws_lb_target_group.alb_target_group.arn
  target_id        = aws_instance.web-server-instance_2.id
  port             = 80
}
```
今回は、異なるAZのサブネット内のEC2にリクエストを分散したいため、ターゲットにそれぞれのEC2を指定する。

### リスナーを設定
続いてリスナーを設定し、ALBがリクエストを受け付けるポートを設定。

```terraform:alb.tf
#HTTPリスナー
resource "aws_lb_listener" "http" {
  load_balancer_arn = aws_lb.alb.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.alb_target_group.id
  }
}
```
- `default_action`（必須項目）  
リスナーは複数のルールを設定して、それぞれの異なるアクションを実行できる。  
今回は、`type="forward"`を設定し、リクエストを上記のターゲットグループに転送。  

ここまでで記述した内容をまとめると、
「__80番ポートで受け付けたHTTPリクエストを、指定したターゲットグループ内のターゲット（EC2）へ分散的にルーティングする。__」となる。
ここで`terraform apply`を実行。

ロードバランサー、ターゲットグループがそれぞれ作成され、リスナーやターゲットが問題なく反映されていることを確認。

### ALBのDNS名からHTTPアクセス確認
マネジメントコンソールで作成したALBの説明タブを開き、DNS名をコピーしブラウザでアクセスしてみる。
ターゲットに指定したどちらかのEC2のindex.htmlが表示されていれば成功。

ページを数回リロードして、リクエストが振り分けられていることも確認できたら、
ALBを使ってアクセス分散は成功！

## 終わりに
ALBの作成までをまとめました。
長くなりそうなので、Route53、ACM設定は続編として別記事にまとめます。
続き→[【AWS】Terraformでアクセスを分散、WebサーバーをHTTPS化する その2(Route53)](https://qiita.com/ramunauna/items/cc85201fb99ef3e6eb95)