Terraform 入門から精通まで（AWS実体験）

## 概要
今回、Terraformを使って、AWS VPCを構築して、VPCのpublic subnetに外部からアクセスできるec2を起動します。

## システム構成図
![截屏2022-07-07 0.01.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2531066/747d23e8-8bbd-e036-126c-4316b3cda96c.png)

## やること
- VPCを構築
- Internet Gatewayを作成
- Route Tableを作成
- サブネットを作成
- Route Tableにサブネットを関連付け
- port22,443,80を許可Security Groupを作成
- network interfaceを作成
- 作成したnetwork interfaceにElastic IPを関連付け
- EC2を作成して、ec2にApacheをインストールして、起動する

## 前提条件
・MAC
・VS code
・リソースを作成するためのAWSの権限設定をもつiamユーザーのアクセスキー
・Terraformをインストール済み
・EC2のキーペアを作成済み

## 参照DOC

https://registry.terraform.io/providers/hashicorp/aws/latest/docs

## ローカルip確認

https://checkip.amazonaws.com/

## VPCを構築

```
## 1.create vpc
resource "aws_vpc" "dev-vpc" {
  cidr_block = "10.0.0.0/16"
}
```
## Internet Gatewayを作成

```
## 2.create Internet Gateway
resource "aws_internet_gateway" "dev-igw" {
  vpc_id = aws_vpc.dev-vpc.id
  tags = {
    Name = "dev-igw"
  }
}
```
## Route Tableを作成
```
#  3.create Custom Route Table
resource "aws_route_table" "dev-route-table" {
  vpc_id = aws_vpc.dev-vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.dev-igw.id
  }

  route {
    ipv6_cidr_block = "::/0"
    gateway_id      = aws_internet_gateway.dev-igw.id
  }

  tags = {
    Name = "dev-route-table"
  }
}
```
## サブネットを作成
```
#  4.create a subnet
resource "aws_subnet" "dev-subnet" {
  vpc_id            = aws_vpc.dev-vpc.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "ap-northeast-1c"

  tags = {
    Name = "dev-subnet"
  }
}
```
## Route Tableにサブネットを関連付け

```
#  5.associate subnet with Route Table
resource "aws_route_table_association" "dev-route-table-association" {
  subnet_id      = aws_subnet.dev-subnet.id
  route_table_id = aws_route_table.dev-route-table.id
}
```
## port22,443,80を許可Security Groupを作成
ローカルIPだけEC2のport22,443,80にアクセス許可します。


xx.xx.xx.xx/32はローカルipです。


```
#  6.create Security Group to allow prot 22,80,443
resource "aws_security_group" "allow_web" {
  name        = "allow_web_traffic"
  description = "Allow web inbound traffic"
  vpc_id      = aws_vpc.dev-vpc.id

  ingress {
    description = "HTTPS"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["xx.xx.xx.xx/32"]
  }
  ingress {
    description = "HTTP"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["xx.xx.xx.xx/32"]
  }
  ingress {
    description = "SSH"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["xx.xx.xx.xx/32"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "allow_web"
  }
}
```
## network interfaceを作成

```
#  7.create a network interface with an ip in the subnet that created in step 4
resource "aws_network_interface" "dev-network-interface" {
  subnet_id       = aws_subnet.dev-subnet.id
  private_ips     = ["10.0.1.50"]
  security_groups = [aws_security_group.allow_web.id]
}
```
## 作成したnetwork interfaceにElastic IPを関連付け
```
#  8.Assign an elastic IP to the network interface created in step7
resource "aws_eip" "one" {
  vpc                       = true
  network_interface         = aws_network_interface.dev-network-interface.id
  associate_with_private_ip = "10.0.1.50"
  depends_on                = [aws_internet_gateway.dev-igw]
}
```
## EC2を作成して、ec2にApacheをインストールして、起動する
```
#  9.create Ec2 server and install/start apache
resource "aws_instance" "dev-web-server" {
  ami               = "ami-0b7546e839d7ace12"
  instance_type     = "t2.micro"
  availability_zone = aws_subnet.dev-subnet.availability_zone
  key_name          = "terraform-key"
  network_interface {
    device_index          = 0
    network_interface_id  = aws_network_interface.dev-network-interface.id
  }
  user_data = <<-EOF
                #!/usr/bin/env bash
                su ec2-user
                sudo yum install httpd -y
                sudo service httpd start
                sudo su -c "cat > /var/www/html/index.html <<EOL
                <html>
                <head>
                    <meta charset="utf-8">
                    <title> call to Arms</title>
                    <style type="text/css"></style>
                </head>
                <body>
                    <img src="https://media.giphy.com/media/rgTB82z9P63fTGhxQo/giphy.gif" height="100%">

                </body>
                </html>
                EOL"
                EOF

  tags = {
    Name = "dev-web-server"
  }
}
```
## main.tfに全てのコード
```
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
}

# Configure the AWS Provider
provider "aws" {
  region     = "ap-northeast-1"
  access_key = "xxxxxxxxxxxx"
  secret_key = "xxxxxxxxxxxxxxx"

}
#  1.create vpc
resource "aws_vpc" "dev-vpc" {
  cidr_block = "10.0.0.0/16"
}
#  2.create Internet Gateway
resource "aws_internet_gateway" "dev-igw" {
  vpc_id = aws_vpc.dev-vpc.id
  tags = {
    Name = "dev-igw"
  }
}
#  3.create Custom Route Table
resource "aws_route_table" "dev-route-table" {
  vpc_id = aws_vpc.dev-vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.dev-igw.id
  }

  route {
    ipv6_cidr_block = "::/0"
    gateway_id      = aws_internet_gateway.dev-igw.id
  }

  tags = {
    Name = "dev-route-table"
  }
}
#  4.create a subnet
resource "aws_subnet" "dev-subnet" {
  vpc_id            = aws_vpc.dev-vpc.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "ap-northeast-1c"

  tags = {
    Name = "dev-subnet"
  }
}
#  5.associate subnet with Route Table
resource "aws_route_table_association" "dev-route-table-association" {
  subnet_id      = aws_subnet.dev-subnet.id
  route_table_id = aws_route_table.dev-route-table.id
}
#  6.create Security Group to allow prot 22,80,443
resource "aws_security_group" "allow_web" {
  name        = "allow_web_traffic"
  description = "Allow web inbound traffic"
  vpc_id      = aws_vpc.dev-vpc.id

  ingress {
    description = "HTTPS"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["xx.xx.xx.xx/32"]
  }
  ingress {
    description = "HTTP"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["xx.xx.xx.xx/32"]
  }
  ingress {
    description = "SSH"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["xx.xx.xx.xx/32"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "allow_web"
  }
}
#  7.create a network interface with an ip in the subnet that created in step 4
resource "aws_network_interface" "dev-network-interface" {
  subnet_id       = aws_subnet.dev-subnet.id
  private_ips     = ["10.0.1.50"]
  security_groups = [aws_security_group.allow_web.id]
}
#  8.Assign an elastic IP to the network interface created in step7
resource "aws_eip" "one" {
  vpc                       = true
  network_interface         = aws_network_interface.dev-network-interface.id
  associate_with_private_ip = "10.0.1.50"
  depends_on                = [aws_internet_gateway.dev-igw]
}
#  9.create Ec2 server and install/start apache
resource "aws_instance" "dev-web-server" {
  ami               = "ami-0b7546e839d7ace12"
  instance_type     = "t2.micro"
  availability_zone = aws_subnet.dev-subnet.availability_zone
  key_name          = "terraform-key"
  network_interface {
    device_index          = 0
    network_interface_id  = aws_network_interface.dev-network-interface.id
  }
  user_data = <<-EOF
                #!/usr/bin/env bash
                su ec2-user
                sudo yum install httpd -y
                sudo service httpd start
                sudo su -c "cat > /var/www/html/index.html <<EOL
                <html>
                <head>
                    <meta charset="utf-8">
                    <title> call to Arms</title>
                    <style type="text/css"></style>
                </head>
                <body>
                    <img src="https://media.giphy.com/media/rgTB82z9P63fTGhxQo/giphy.gif" height="100%">

                </body>
                </html>
                EOL"
                EOF

  tags = {
    Name = "dev-web-server"
  }
}
```
## Terraformを実行
```
terraform apply
```

## 結果を確認
Ec2を起動成功
![截屏2022-07-07 0.17.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2531066/afdfe207-db76-8513-513b-b0fde7dc4717.png)
パブリック IPv4にアクセスして、成功
![截屏2022-07-07 0.18.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2531066/47cd41b1-8a4d-4f5f-a95b-edfc7908001a.png)
SSH接続テスト
```
% ssh -i "terraform-key.pem" ec2-user@35.79.171.109
The authenticity of host '35.79.171.109 (35.79.171.109)' can't be established.
ED25519 key fingerprint is SHA256:1pBw7U6RD6sluMPNs3Lk4gzHRooDIGtuVq7Ld5P1mEE.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '35.79.171.109' (ED25519) to the list of known hosts.
Last login: Wed Jul  6 11:06:32 2022

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory
[ec2-user@ip-10-0-1-50 ~]$ 
```
無事にローカルからec2にsshしました。

## 片付ける
以下のコマンドで今回作成したインフラを削除します。
```
terraform destroy --auto-approve
```
以上となります。