wordpressサイトをterraformで構築する

#本記事のゴール
https://qiita.com/chanP_yamazaki/items/3691d624a3510236458a

「AWSでwordpressを動かす」1~5までの内容をほぼほぼ網羅した構成をterraformで構築する

# 参考資料
https://registry.terraform.io/providers/hashicorp/aws/latest/docs

#terraformのインストール
インストール
公式サイトからバイナリをDLして解凍
https://learn.hashicorp.com/tutorials/terraform/install-cli

```
$ mkdir -p ~/Applications/terraform
$ mv DLしたterraformファイル ~/Applications/terraform/
$ export PATH=$PATH:~/Applications/terraform/
```

#プロジェクトのディレクトリ構成
```
project
　┣━ main.tf
　┣━ network.tf
　┣━ security_group.tf
　┣━ key.tf
　┣━ ec2.tf
　┣━ loadbalancer.tf
　┣━ rds.tf
　┣━ cloudfront.tf
　┣━ scripts
　┃　　　　　　┣━ apache.sh
　┃　　　　　　┣━ ftp.sh
　┃　　　　　　┣━ mysql.sh
　┃　　　　　　┣━ nfs_master.sh
　┃　　　　　　┣━ nfs_slave_org.sh
　┃　　　　　　┣━ php-fpm.sh
　┃　　　　　　┣━ postfix.sh
　┃　　　　　　┣━ timezone.sh
　┃　　　　　　┣━ wordpress_master.sh
　┃　　　　　　┗━ wordpress_slave.sh
　┃
　┗━ sshKey
　　　　　　　　┣━ pubKey
　　　　　　　　┗━ id_rsa
```

# 鍵ファイルの配置
新規に鍵を作成 or 既存の鍵を再利用どちらでも良いので、キーペアをプロジェクトのsshkeyディレクトリ下に配置
公開鍵名称: pubKey
秘密鍵名称: id_rsa

# 各ファイル
``` main.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.27"
    }
  }

  required_version = ">= 0.14.9"
}

provider "aws" {
  access_key = "hogehoge"
  secret_key = "hogehoge"
  profile = "default"
  region  = "ap-northeast-1"
}
```

``` network.tf
resource "aws_vpc" "wordpress_vpc" {
    cidr_block = "10.100.0.0/16"
    instance_tenancy = "default"
    enable_dns_support = "true"
    enable_dns_hostnames = "true"
    tags = {
      Name = "wordpress_vpc"
    }
}

resource "aws_internet_gateway" "wordpress_gw" {
    vpc_id = "${aws_vpc.wordpress_vpc.id}"
}

resource "aws_subnet" "public-a" {
    vpc_id = "${aws_vpc.wordpress_vpc.id}"
    cidr_block = "10.100.1.0/24"
    availability_zone = "ap-northeast-1a"
}

resource "aws_subnet" "public-c" {
    vpc_id = "${aws_vpc.wordpress_vpc.id}"
    cidr_block = "10.100.2.0/24"
    availability_zone = "ap-northeast-1c"
}

resource "aws_subnet" "private-a" {
    vpc_id = "${aws_vpc.wordpress_vpc.id}"
    cidr_block = "10.100.3.0/24"
    availability_zone = "ap-northeast-1a"
}

resource "aws_subnet" "private-c" {
    vpc_id = "${aws_vpc.wordpress_vpc.id}"
    cidr_block = "10.100.4.0/24"
    availability_zone = "ap-northeast-1c"
}

resource "aws_route_table" "public-route" {
    vpc_id = "${aws_vpc.wordpress_vpc.id}"
    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = "${aws_internet_gateway.wordpress_gw.id}"
    }
}

resource "aws_route_table_association" "puclic-a" {
    subnet_id = "${aws_subnet.public-a.id}"
    route_table_id = "${aws_route_table.public-route.id}"
}

resource "aws_route_table_association" "puclic-c" {
    subnet_id = "${aws_subnet.public-c.id}"
    route_table_id = "${aws_route_table.public-route.id}"
}
```

``` security_group.tf
resource "aws_security_group" "all_ssh" {
  name = "ssh-sg"
  vpc_id = "${aws_vpc.wordpress_vpc.id}"
  egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_security_group_rule" "all_ssh_inbound1" {
  type        = "ingress"
  from_port   = 22
  to_port     = 22
  protocol    = "tcp"
  cidr_blocks = [
    "0.0.0.0/0"
  ]

  security_group_id = "${aws_security_group.all_ssh.id}"
}

resource "aws_security_group" "all_vpc" {
  name = "all_vpc"
  vpc_id = "${aws_vpc.wordpress_vpc.id}"
  egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["10.100.0.0/16"]
  }
}

resource "aws_security_group" "all_web" {
  name = "all-web"
  vpc_id = "${aws_vpc.wordpress_vpc.id}"
  egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_security_group_rule" "all_web_inbound1" {
  type        = "ingress"
  from_port   = 80
  to_port     = 80
  protocol    = "tcp"
  cidr_blocks = [
    "0.0.0.0/0"
  ]

  security_group_id = "${aws_security_group.all_web.id}"
}

resource "aws_security_group" "all_ftp" {
  name = "ftp-web"
  vpc_id = "${aws_vpc.wordpress_vpc.id}"
  egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_security_group_rule" "all_ftp_inbound1" {
  type        = "ingress"
  from_port   = 21
  to_port     = 21
  protocol    = "tcp"
  cidr_blocks = [
    "0.0.0.0/0"
  ]

  security_group_id = "${aws_security_group.all_ftp.id}"
}

resource "aws_security_group_rule" "all_ftp_inbound2" {
  type        = "ingress"
  from_port   = 60001
  to_port     = 60010
  protocol    = "tcp"
  cidr_blocks = [
    "0.0.0.0/0"
  ]

  security_group_id = "${aws_security_group.all_ftp.id}"
}
```

``` key.tf
resource "aws_key_pair" "ssh_key" {
  key_name   = "ssh_key"
  public_key = file("./sshKey/pubKey")
}
```

``` ec2.tf
resource "aws_instance" "master_server" {
  ami           = "ami-0b276ad63ba2d6009"
  instance_type = "t2.micro"
  associate_public_ip_address = true
  vpc_security_group_ids = [
    "${aws_security_group.all_web.id}",
    "${aws_security_group.all_ssh.id}",
    "${aws_security_group.all_ftp.id}",
    "${aws_security_group.all_vpc.id}"
  ]
  subnet_id = "${aws_subnet.public-a.id}"
  key_name = "${aws_key_pair.ssh_key.id}"
  tags = {
    Name = "wordpress_master"
  }

  provisioner "remote-exec" {
    connection {
      type = "ssh"
      user = "ec2-user"
      host = "${self.public_ip}"
      private_key = file("./sshKey/id_rsa")
    }
    scripts = [
      "./scripts/timezone.sh",
      "./scripts/apache.sh",
      "./scripts/mysql.sh",
      "./scripts/php-fpm.sh",
      "./scripts/wordpress_master.sh",
      "./scripts/ftp.sh",
      "./scripts/postfix.sh",
      "./scripts/nfs_master.sh"
    ]
  }

  provisioner "local-exec" {
    command = "cp scripts/nfs_slave_org.sh scripts/nfs_slave.sh; sed -ie 's|<MASTER_PRIVATE_IP>|${self.private_ip}|' scripts/nfs_slave.sh"
  }
}

resource "aws_instance" "slave_server" {
  ami           = "ami-0b276ad63ba2d6009"
  instance_type = "t2.micro"
  associate_public_ip_address = true
  vpc_security_group_ids = [
    "${aws_security_group.all_ssh.id}",
    "${aws_security_group.all_vpc.id}"
  ]
  subnet_id = "${aws_subnet.public-a.id}"
  key_name = "${aws_key_pair.ssh_key.id}"
  tags = {
    Name = "wordpress_slave"
  }

  provisioner "remote-exec" {
    connection {
      type = "ssh"
      user = "ec2-user"
      host = "${self.public_ip}"
      private_key = file("./sshKey/id_rsa")
    }
    scripts = [
      "./scripts/timezone.sh",
      "./scripts/apache.sh",
      "./scripts/mysql.sh",
      "./scripts/php-fpm.sh",
      "./scripts/wordpress_slave.sh",
      "./scripts/nfs_slave.sh"
    ]
  }
  depends_on = [
    aws_instance.master_server
  ]
}
```

``` loadbalancer.tf
resource "aws_lb_target_group" "wordpress_tg" {
  name     = "wordpress"
  port     = 80
  protocol = "HTTP"
  vpc_id   = "${aws_vpc.wordpress_vpc.id}"
}

resource "aws_lb_target_group_attachment" "wordpress_tg1" {
  target_group_arn = "${aws_lb_target_group.wordpress_tg.arn}"
  target_id        = "${aws_instance.master_server.id}"
  port             = 80
}

resource "aws_lb_target_group_attachment" "wordpress_tg2" {
  target_group_arn = "${aws_lb_target_group.wordpress_tg.arn}"
  target_id        = "${aws_instance.slave_server.id}"
  port             = 80
}

resource "aws_lb_target_group" "wordpress_master_tg" {
  name     = "wordpress-master"
  port     = 80
  protocol = "HTTP"
  vpc_id   = "${aws_vpc.wordpress_vpc.id}"
}

resource "aws_lb_target_group_attachment" "wordpress_master_tg1" {
  target_group_arn = "${aws_lb_target_group.wordpress_master_tg.arn}"
  target_id        = "${aws_instance.master_server.id}"
  port             = 80
}

resource "aws_lb" "wordpress_lb" {
  name               = "wordpress"
  internal           = false
  load_balancer_type = "application"
  security_groups    = ["${aws_security_group.all_web.id}"]
  subnets            = ["${aws_subnet.public-a.id}", "${aws_subnet.public-c.id}"]
}

resource "aws_lb_listener" "wordpress_lb_listener" {
  load_balancer_arn = "${aws_lb.wordpress_lb.arn}"
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = "${aws_lb_target_group.wordpress_tg.arn}"
  }
}

resource "aws_alb_listener_rule" "rule_login" {
  listener_arn = "${aws_lb_listener.wordpress_lb_listener.arn}"
  priority = 1

  action {
    type             = "forward"
    target_group_arn = "${aws_lb_target_group.wordpress_master_tg.arn}"
  }

  condition {
    path_pattern {
      values = ["/wp-login.php"]
    }
  }
}

resource "aws_alb_listener_rule" "rule_admin" {
  listener_arn = "${aws_lb_listener.wordpress_lb_listener.arn}"
  priority = 2

  action {
    type             = "forward" 
    target_group_arn = "${aws_lb_target_group.wordpress_master_tg.arn}"
  }

  condition {
    path_pattern {
      values = ["/wp-admin/*"]
    }
  }
}
```

``` rds.tf
resource "aws_db_subnet_group" "wordpress_db_subnet" {
  name       = "wordpress"
  subnet_ids = ["${aws_subnet.private-a.id}", "${aws_subnet.private-c.id}"]
}

resource "aws_rds_cluster" "wordpress_clustor" {
  cluster_identifier      = "wordpress"
  engine                  = "aurora-mysql"
  engine_version          = "5.7.mysql_aurora.2.10.0"
  db_subnet_group_name    = "${aws_db_subnet_group.wordpress_db_subnet.id}"
  availability_zones      = ["ap-northeast-1a"]
  database_name           = "wordpress"
  master_username         = "root"
  master_password         = "wordpress"
  skip_final_snapshot     = "true"
  vpc_security_group_ids  = ["${aws_security_group.all_vpc.id}"]
}

resource "aws_rds_cluster_instance" "wordpress_clustor_instance" {
  count              = 1
  identifier         = "wordpress-db"
  cluster_identifier = "${aws_rds_cluster.wordpress_clustor.id}"
  instance_class     = "db.t3.small"
  engine             = "${aws_rds_cluster.wordpress_clustor.engine}"
  engine_version     = "${aws_rds_cluster.wordpress_clustor.engine_version}"
  availability_zone  = "ap-northeast-1a"
}
```

``` cloudfront.tf
resource "aws_cloudfront_distribution" "wordpress_cf" {
  enabled             = true
  is_ipv6_enabled     = false  

  origin {
    domain_name = "${aws_lb.wordpress_lb.dns_name}"
    origin_id   = "${aws_lb.wordpress_lb.id}"

    custom_origin_config {
      http_port              = 80
      https_port             = 443
      origin_protocol_policy = "http-only"
      origin_ssl_protocols   = ["TLSv1", "TLSv1.1", "TLSv1.2"]
    }
  }

  default_cache_behavior {
    allowed_methods  = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = "${aws_lb.wordpress_lb.id}"

    forwarded_values {
      query_string = true

      headers = ["Host", "CloudFront-Forwarded-Prot"]

      cookies {
        forward = "all"
      }
    }

    viewer_protocol_policy = "allow-all"
    min_ttl                = 0
    default_ttl            = 0
    max_ttl                = 0
  }

  ordered_cache_behavior {
    path_pattern     = "wp-content/uploads/*"
    allowed_methods  = ["GET", "HEAD"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = "${aws_lb.wordpress_lb.id}"

    forwarded_values {
      query_string = false

      headers = ["Host", "CloudFront-Forwarded-Prot"]

      cookies {
        forward = "none"
      }
    }

    viewer_protocol_policy = "allow-all"
    min_ttl                = 86400
    default_ttl            = 86400
    max_ttl                = 86400
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }
}
```

``` apache.sh
#!/bin/sh
sudo yum -y update
sudo yum install -y httpd
sudo cp /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.org
sudo systemctl start httpd
sudo systemctl enable httpd
```

``` ftp.sh
#!/bin/sh

sudo yum install -y vsftpd
sudo cp /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.org
sudo sed -i 's|anonymous_enable=YES|anonymous_enable=NO|' /etc/vsftpd/vsftpd.conf
sudo sed -i 's|#chroot_local_user=YES|chroot_local_user=YES|' /etc/vsftpd/vsftpd.conf
sudo sed -i 's|#chroot_list_enable=YES|chroot_list_enable=YES|' /etc/vsftpd/vsftpd.conf
sudo sed -i 's|listen=NO|listen=YES|' /etc/vsftpd/vsftpd.conf
sudo sed -i 's|listen_ipv6=YES|listen_ipv6=NO|' /etc/vsftpd/vsftpd.conf
sudo sed -i 's|tcp_wrappers=YES|tcp_wrappers=NO|' /etc/vsftpd/vsftpd.conf
echo -e "pasv_enable=YES\npasv_addr_resolve=YES\npasv_min_port=60001\npasv_max_port=60010\nuse_localtime=YES\nforce_dot_files=YES\nallow_writeable_chroot=YES" | sudo tee -a /etc/vsftpd/vsftpd.conf
sudo touch /etc/vsftpd/chroot_list
sudo systemctl start vsftpd
sudo systemctl enable vsftpd
```

``` mysql.sh
#!/bin/sh
sudo yum remove -y mariadb*
sudo yum install -y http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm
sudo yum-config-manager --disable mysql55-community
sudo yum-config-manager --enable mysql56-community
sudo yum -y install mysql mysql-devel mysql-server mysql-utilities
sudo cp /etc/my.cnf /etc/my.cnf.org
echo -e "character_set_server=utf8\nskip-character-set-client-handshake" | sudo tee -a /etc/my.cnf
```

``` nfs_master.sh
#!/bin/sh

echo "/home/wordpress/wordpress *(rw,no_root_squash)" | sudo tee -a /etc/exports
sudo exportfs -ra
sudo systemctl restart nfs
sudo systemctl enable nfs
```

``` nfs_slave_org.sh
#!/bin/sh

echo "<MASTER_PRIVATE_IP>:/home/wordpress/wordpress /home/wordpress/wordpress nfs4 defaults 0 0" | sudo tee -a /etc/fstab
sudo mount /home/wordpress/wordpress
```

``` php-fpm.sh
#!/bin/sh
sudo amazon-linux-extras install -y epel
sudo yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
sudo yum install -y --enablerepo=remi-php70 php70-php php70-php-common php70-php-pdo php70-php-cli php70-php-mbstring php70-php-xml php70-php-mysqlnd php70-php-json php70-php-process
cat /opt/remi/php70/enable | sudo tee -a /etc/bashrc
sudo source /etc/bashrc
sudo cp /etc/opt/remi/php70/php.ini /etc/opt/remi/php70/php.ini.org
sed -i 's|;date\.timezone\s*=\s*.*|date\.timezone = "Asia/Tokyo"|' /etc/opt/remi/php70/php.ini
sudo systemctl restart httpd
sudo echo '<?php phpinfo();' | sudo tee /var/www/html/index.php
```

``` postfix.sh
#!/bin/sh

sudo yum install -y postfix
sudo systemctl enable postfix
sudo systemctl restart postfix
sudo postmap /etc/postfix/virtual
sudo update-alternatives --set mta /usr/sbin/sendmail.postfix
```

``` timezone.sh
#!/bin/sh

sudo ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
echo -e "ZONE="Asia/Tokyo"\nUTC=False" | sudo tee /etc/sysconfig/clock
```

``` wordpress_master.sh
#!/bin/bash

sudo useradd -m wordpress
echo wordpress | sudo passwd --stdin wordpress
sudo chmod 775 /home/wordpress

sudo cd /tmp
sudo wget http://ja.wordpress.org/wordpress-4.9.4-ja.tar.gz
sudo tar zxvf wordpress-4.9.4-ja.tar.gz
sudo mv wordpress /home/wordpress/
sudo chown wordpress:wordpress -R /home/wordpress/wordpress
sudo ln -s /home/wordpress/wordpress /var/www/wordpress
sudo chown -R wordpress:wordpress /var/www/wordpress
sudo sed -i 's|DocumentRoot \"/var/www/html\"|DocumentRoot \"/var/www/wordpress\"|' /etc/httpd/conf/httpd.conf
sudo systemctl restart httpd
```

``` wordpress_slave.sh
#!/bin/sh

sudo useradd -m wordpress
echo wordpress | sudo passwd --stdin wordpress
sudo mkdir /home/wordpress/wordpress
sudo chmod 775 -R /home/wordpress

sudo chown wordpress:wordpress -R /home/wordpress/wordpress
sudo ln -s /home/wordpress/wordpress /var/www/wordpress
sudo chown -R wordpress:wordpress /var/www/wordpress
sudo sed -i 's|DocumentRoot \"/var/www/html\"|DocumentRoot \"/var/www/wordpress\"|' /etc/httpd/conf/httpd.conf
sudo systemctl restart httpd
```

# terraform実行ユーザーの作成
「AmazonRDSFullAccess / AmazonEC2FullAccess / CloudFrontFullAccess」付きのユーザーを作成し、アクセスキーも作成、その後main.tfにアクセスキー情報を記載する

# terraform実行
```
$ terraform init
$ terraform apply
```
5分程度で立ち上がります

# 注意点
セキュリティグループは必要最低限のIPに調整してください