aws上に作成したansibleサーバーでテストサイトを構築する(2) AWSネットワーク構成

# はじめに
[前回](https://qiita.com/yoshino_dd/items/1e0969fd6dab1b51e1e0)はAnsibleサーバーの構築を実施しました。
今回は構築したAndibleを使ってAWS上にVPCなどのネットワークリソースやキーペアの作成を行います。

- aws上に作成したansibleサーバーでテストサイトを構築する
  1. [Ansibleサーバー構築](https://qiita.com/yoshino_dd/items/1e0969fd6dab1b51e1e0)
  1. [AWSネットワーク構成](https://qiita.com/yoshino_dd/items/d9be528837803ebb4bd3)
  1. [EC2インスタンスの作成](https://qiita.com/yoshino_dd/items/4368e468c6aa5353bf3c)
  1. [サーバー共通の設定](https://qiita.com/yoshino_dd/items/3fa56fc09e9162d6ad4a)
  1. [Webサーバーの構成](https://qiita.com/yoshino_dd/items/1292d6b3beeae26433f7)
  1. [RDSの構成-1](https://qiita.com/yoshino_dd/items/8d559b60d5b9f316d8bb)
  1. [RDSの構成-2](https://qiita.com/yoshino_dd/items/1da42dc2d1446ec20526)
  1. [WordPressの設定](https://qiita.com/yoshino_dd/items/d41694d468c5c64d78a0)
  1. 参考にしたサイトなど

# Playbookの作成
まずはPlaybookを格納するディレクトリを作成します。今後はすべてここを基準に作成、実行していきます。
大まかなレイアウトは[ここ](http://docs.ansible.com/ansible/latest/playbooks_best_practices.html#directory-layout)に記載されているものと合わせるようにしています。

```shell-session:command
> mkdir aws_testsite
> cd aws_testsite
```

次に`ansible-playbook`コマンドから呼び出すおおもとのPlaybookファイル`site.yml`を作成します。
AWSのリソースを作成する部分と、作成したEC2インスタンス上の設定(OSやミドルウェア等)を行う部分とに分けて別々に実行できるようにしようと思いますので、このファイルからは子ファイルを呼び出すのみとします。

```yaml:site.yml
- import_playbook: aws_infra.yml
```

呼び出される子のPlaybookは以下のように、`aws_network`ロールを呼び出すものとします。ここには今後、EC2インスタンスやRDSインスタンスの作成ロールを追加していきます。

```yaml:aws_infta.yml
- hosts: localhost
  roles:
  - { role: aws_network, tags: [aws_network] }
```

Playbookで指定した通り、`aws_network`ロールを`roles`フォルダ配下に作ります。

```shell-session:command
> mkdir -p roles/aws_network/tasks
```

# ネットワークリソースの内容の定義
どのようなネットワーク構成にするかを`group_vars`フォルダの`all.yml`ファイルに定義します。
ここでは、アジアパシフィック（東京）リージョン`ap-northeast-1`にVPCを作成して、中のAZそれぞれにwebapp用のサブネットを一つづつ作ることにします。

```shell-session:command
> mkdir -p group_vars
```
```yaml:group_vars/all.yml
---
vpc:
  name: "testsite"
  region: "ap-northeast-1"
  cidr: "172.22.0.0/16"
  subnets:
  - name: "webapp1"
    cidr: "172.22.1.0/24"
    az: "ap-northeast-1a"
  - name: "webapp2"
    cidr: "172.22.2.0/24"
    az: "ap-northeast-1c"
```

# 各リソースを作成するタスクの作成
`group_vars/all.yml`で定義した内容に従って、各リソースを作成するタスクを作ります。
VPC等のネットワークリソースを作成するタスクは相互のかかわりが大きいので`create_vpc.yml`として1つのファイルにまとめます。

```YAML:roles/aws_network/tasks/main.yml
---
- import_tasks: create_vpc.yml
```

## VPCの作成
まずVPCを作成します。テストサイトを構成するPlaybookなので、複数のVPCを作成することは考慮しません。

```yaml:roles/aws/tasks/create_vpc.yml
---
- name: create vpc
  ec2_vpc_net:
    state: present
    region: "{{ vpc.region }}"
    cidr_block: "{{ vpc.cidr }}"
    name: "{{ vpc.name }}"
  register: aws_network_vpc

- debug: var=aws_network_vpc
```

ここまでのPlaybookを実行すると以下のようになります。

```shell-session:command
$ ansible-playbook site.yml 

PLAY [localhost] *************************************************************************************************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************************************************************************************************
ok: [localhost]

TASK [aws_network : create vpc] **********************************************************************************************************************************************************************
changed: [localhost]

TASK [aws_network : debug] ***************************************************************************************************************************************************************************
ok: [localhost] => {
    "aws_vpc": {
        "changed": false, 
        "failed": false, 
        "vpc": {
            "cidr_block": "172.22.0.0/16", 
            "classic_link_enabled": null, 
            "dhcp_options_id": "dopt-f6c50e92", 
            "id": "vpc-603e2404", 
            "instance_tenancy": "default", 
            "is_default": false, 
            "state": "available", 
            "tags": {
                "Name": "testsite"
            }
        }
    }
}
```

## サブネットの作成
続いてVPC内にサブネットを作成します。こちらは複数のサブネットを構成するので`with_items`で複数のサブネットを作成します。
引数として前タスクで作成したVPCのIDが必要となりますので、`register`ディレクティブで確保した`aws_network_vpc`から取得します。

```yaml:roles/aws/tasks/create_vpc.yml(追記)
- name: create vpc subnets
  ec2_vpc_subnet:
    state: present
    vpc_id: "{{ aws_network_vpc.vpc.id }}"
    region: "{{ vpc.region }}"
    cidr: "{{ item.cidr }}"
    az: "{{ item.az }}"
    tags:
      Name: "{{ item.name }}"
  with_items: "{{ vpc.subnets }}"
```

## インターネットゲートウェイの作成
このVPC内とインターネット間での通信ができるようにインターネットゲートウェイを作成します。
インターネットからのWebアクセスやSSH接続、また内部からインターネットの参照に使用します。
ここでもVPC IDが必要となります。

```yaml:roles/aws/tasks/create_vpc.yml(追記)
- name: create internet gateway
  ec2_vpc_igw:
    state: present
    region: "{{ vpc.region }}"
    vpc_id: "{{ aws_network_vpc.vpc.id }}"
  register: aws_igw
```

## ルートテーブルの作成
各サブネットにインターネット参照を可能とするルートテーブルを定義します。
今回の構成では、すべてのサーバーをAnsibleで管理するためにインターネットからのSSH接続が必要となるため、作成したサブネットすべてにインターネット向けのルートを設定します。

ルートテーブルに登録するサブネット名のリストが必要となるため、`group_vars/all.yml`の定義から、サブネット名のリストを作成しています。

```yaml:roles/aws_network/tasks/create_vpc.yml(追記)
- name: make subnet list
  set_fact:
    list_subnets: "{{ vpc.subnets | map(attribute='name') | list }}"

- name: Set up public subnet route table
  ec2_vpc_route_table:
    state: present
    region: "{{ vpc.region }}"
    vpc_id: "{{ aws_network_vpc.vpc.id }}"
    tags:
      Name: "Public subnet"
    subnets: "{{ list_subnets }}"
    routes:
      - dest: 0.0.0.0/0
        gateway_id: "{{ aws_igw.gateway_id }}"
```

## セキュリティグループの作成
続いて作成するWEBサーバーへのアクセスを制御するためのセキュリティグループを定義します。
まずはAnsibleサーバーからのSSH接続を可能にするために、「0.0.0.0/0」からのSSH(TCP/22)接続を許可します。
EC2は停止するたびにグローバルIPアドレスが変わるため、全アドレスからのSSHを許可しています。
EC2のSSHは既定で公開鍵認証のみが有効となるので、テストサイトであれば問題ないでしょう…
(SSHに脆弱性が発見される可能性もあるので本番サイトの場合はまた別に考える必要があります)

Webアプリへの接続を許可するルールも定義しておきます。
こちらは接続元のIPを限定して許可する設定としています。これは、AWS上でWebサーバーを公開すると、すぐにWordPressやphpMyAdminへのアタックと思われるアクセスがあるためです。
複数の接続元がある場合には、それぞれルールを定義します。(Ansible 2.4になればcidr_ipや、portをリスト構成にできるようになるようです)

```yaml:group_vars/all.yml(追記)
security_groups:
  - name: "SG_webapps"
    description: "for WebApplication Servers"
    rules:
    - proto: tcp
      from_port: 22
      to_port: 22
      cidr_ip: 0.0.0.0/0
    - proto: tcp
      from_port: 80
      to_port: 80
      cidr_ip: x.x.x.x/32
    - proto: tcp
      from_port: 80
      to_port: 80
      cidr_ip: y.y.y.y/32
```
```yaml:roles/aws_network/tasks/create_vpc.yml(追記)
- name: create security group
  ec2_group:
    name: "{{ item.name }}"
    description: "{{ item.description }}"
    vpc_id: "{{ aws_network_vpc.vpc.id }}"
    region: "{{ vpc.region }}"
    rules: "{{ item.rules }}"
  with_items: "{{ security_groups }}"
```

## キーペアの作成
EC2インスタンスにアクセスするキーペアを作成するタスクを作成します。
秘密鍵は、実行ユーザー(ec2-user)の`~/.ssh`に保存するようにしています。

```YAML:roles/aws_network/tasks/main.yml
---
- import_tasks: create_vpc.yml
- import_tasks: create_keypair.yml
```
```yaml:group_vars/all.yml(追加分)
keypair:
  name: "testsite_key"

ssh_keyfile_path: '~/.ssh'
ansible_ssh_private_key_file: '{{ ssh_keyfile_path }}/{{ keypair.name }}.pem'
```
```YAML:roles/aws_network/tasks/create_keypair.yml
---
- name: create keypair
  ec2_key:
    name: "{{ keypair.name }}"
    region: "{{ vpc.region }}"
  register: aws_keypair
```

```YAML:roles/aws_network/tasks/create_keypair.yml(追記)
- name: create keypair file
  file:
    path: '{{ ansible_ssh_private_key_file }}'
    state: touch
    mode: 0600
  when: aws_keypair.key.private_key is defined

- name: keypair write
  shell: echo "{{ aws_keypair.key.private_key }}" > {{ ansible_ssh_private_key_file }}
  delegate_to: 127.0.0.1
  when: aws_keypair.key.private_key is defined
```

# 次回
次回は EC2インスタンスを作成します。

- [aws上に作成したansibleサーバーでテストサイトを構築する(3) EC2インスタンスの作成](https://qiita.com/yoshino_dd/items/4368e468c6aa5353bf3c)

---