【AWS・Ansible】コマンド１つでAmazon VPC構築

2020/06/12
Ansibieはナンセンス！
Terraformで書きましょう！
ーーーーーーーーーーーーー

構成管理ツールAnsibleを使って、以下のAWSサービスを構築します。

- VPC
- Subnet
- Internet Gateway
- Nat Gateway
- Route Table
- Security Group

後述する「事前準備」が完了しましたら、
以下のコマンドで、いつでも同様の環境が作れるようになります。

# 実行コマンド

```
$ ansible-playbook -i hosts/[環境名] aws-vpc.yml
```

実行には、aws profileの設定が必要になります。
AWSアカウント情報をパラメータファイルに記載し実行することも可能ですが、
セキュリティ面を考慮し、aws profileを使用しました。

まだ設定されていない方は、以下の公式ドキュメントを参考に設定を行ってください。

[名前付きプロファイル - AWS CLI の設定](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-multiple-profiles.html)



# 事前準備

以下が必要になります。
足りないのもは、インストールしてください。

- boto
- boto3
- botocore
- python >= 2.6
- Jinja2


次に、以下のファイルを作成しましょう。

## Playbookファイル

このファイルでは、実行Taskを定義します。
コマンド実行時に、このファイルを指定することによって、ファイル内に定義されたTaskが上から順に実行されます。

構築不要のものがあれば、適時、コメントアウトしてください。

```aws-vpc.yml
---
- hosts: localhost
  connection: local
  gather_facts: False
  become: False
  tasks:
    # VPC
    - name: "VPC"
      ec2_vpc_net:
        name: "{{ item.name }}"
        cidr_block: "{{ item.cidr_blodk }}"
        profile: "{{ profile }}"
        region: "{{ region }}"
      with_items: "{{ subnet }}"
      register: _vpc
    - debug: var=_vpc verbosity=1

    # Subnet
    - name: "Subnet"
      ec2_vpc_subnet:
        vpc_id: "{{ _vpc.vpc.id }}"
        az: "{{ item.az }}"
        cidr: "{{ item.cidr }}"
        resource_tags: "{{ item.resource_tags }}"
        profile: "{{ profile }}"
        region: "{{ region }}"
      with_items: "{{ subnet }}"
      register: _subnet
    - debug: var=_subnet verbosity=1

    # Internet Gateway
    - name: "Internet Gateway"
      ec2_vpc_igw:
        vpc_id: "{{ _vpc.vpc.id }}"
        profile: "{{ profile }}"
        region: "{{ region }}"
      register: _igw
    - debug: var=_igw verbosity=1

    # NAT Gateway
    - name: "NAT Gateway"
      ec2_vpc_nat_gateway:
        state: present
        subnet_id: "{{ _subnet.results | selectattr('item.name', 'equalto', item.name) | map(attribute='subnet.id') | first }}"
        if_exist_do_not_create: true
        profile: "{{ profile }}"
        region: "{{ region }}"
      with_items: "{{ subnet }}"
      when: item.nat_gw == true
      register: _nat_gateway
    - debug: var=_nat_gateway verbosity=1

    # Route Table: Public
    - name: "Route Table: Public"
      ec2_vpc_route_table:
        vpc_id: "{{ _vpc.vpc.id }}"
        tags: "{{ item.tags }}"
        subnets: "{{ _subnet.results | selectattr('item.route', 'equalto', 'Public') | map(attribute='subnet.id') | list }}"
        routes:
          - dest: 0.0.0.0/0
            gateway_id: "{{ _igw.gateway_id  }}"
        profile: "{{ profile }}"
        region: "{{ region }}"
      with_items: "{{ route_table_public }}"
      register: _route_table_public
    - debug: var=_route_table_public verbosity=1

    # Route Table: NAT
    - name: "Route Table: NAT"
      ec2_vpc_route_table:
        vpc_id: "{{ _vpc.vpc.id }}"
        tags: "{{ item.tags }}"
        subnets: "{{ _subnet.results | selectattr('item.route', 'equalto', 'NAT') | map(attribute='subnet.id') | list }}"
        routes:
          - dest: 0.0.0.0/0
            gateway_id: "{{ _nat_gateway.results | selectattr('item.nat_gw', 'equalto', true) | map(attribute='nat_gateway_id') | first }}"
        profile: "{{ profile }}"
        region: "{{ region }}"
      with_items: "{{ route_table_nat }}"
      register: _route_table_nat
    - debug: var=_route_table_nat verbosity=1

    # Security Group
    - name: "Security Group"
      ec2_group: 
        name: "{{ item.name }}"
        description: "{{ item.description }}"
        vpc_id: "{{ _vpc.vpc.id }}"
        rules: "{{ item.rules }}"
        tags: "{{ item.tags }}"
        profile: "{{ profile }}"
        region: "{{ region }}"
      with_items: "{{ security_group }}"
      register: _group
    - debug: var=_group verbosity=1
```

## パラメータファイル

基盤構築する際の設定パラメータをこのファイルに集約します。
構築したい環境に合わせて、パラメータを記載してください。

なお、ファイルの配置先は、環境名に合わせて配置してください。

環境別にフォルダを分けて、パラメータファイルを作成することで、
開発/検証/本番 環境など、各環境に応じて動的に構築可能となります。

```hosts/[環境名]/group_vars/all.yml
---
env: [環境名]
Env: "{{ env.capitalize() }}"
profile: [プロファイル名]
region: [リージョン]

# VPC
vpc:
  name: [VPC名]
  cidr_blodk: [VPC CIDRブロック]

# Subnet
subnet:
  - name: [Subnet名]
    az: [アベイラビリティーゾーン]
    cidr: [Subnet CIDRブロック]
    route: [Public or Private]
    nat_gw: [true or flase]
    ・
    ・
    ・

# Route Table: Public
route_table_public:
  tags:
    Name: [Route Table名]
    Env: "{{ env }}"
    ・
    ・
    ・

# Route Table: NAT
route_table_nat:
  tags:
    Name: [Route Table名]
    Env: "{{ env }}"
    ・
    ・
    ・

# Security Group
security_group:
  - name: [Security Group名]
    description: [説明]
    rules:
      - proto: [all or tcp or udp or icmp]
        ports: [ポート番号]
        cidr_ip: [許可するCIDRブロック]
        ・
        ・
        ・
    tags:
      Name: [Security Group名]
      Env: "{{ env }}"
    ・
    ・
    ・
```

# おわりに

今回は、構成管理ツールAnsibleを使いましたが、
AWSのCloud formationでも、同様のことができます。

ただ、Ansibleの場合、システム内構築（SSH、OSユーザーなど）なども定義することができ、
おすすめのツールです。


Ansibleの良いところは、
事前にTaskさえ定義しておけば、後はプロジェクトや環境に合わせて設定パラメータを用意するだけ。
簡単に基盤構築ができてしまうところです。

AWS Consoleから手作業で構築するより、
Ansibleで構築した方が、工数を3分の1にも短縮することができます。


お仕事で、AWSの基盤構築されてる方は、是非、Ansibleを活用してみてください。