AnsibleでAWS操作　Simple Email Service編

# AnsibleでAWS操作シリーズ

1. [aws-cliインストール編](http://qiita.com/bakira/items/d94fc79a032b117bf87f)
1. [EC2インスタンス編](http://qiita.com/bakira/items/ae56e8e03eed4dc75a01)
1. [S3バケット編](http://qiita.com/bakira/items/a1dfe79cfd0e3acaa1a6)
1. [CloudFrontディストリビューション編](http://qiita.com/bakira/items/611e3a51677b751f8366)
1. Simple Email Service編
1. [Certificate Manager編](http://qiita.com/bakira/items/50bdd853ce71953e1600)
1. [Lambda編](https://qiita.com/bakira/items/d55c91328cd1f0ee9581)

# 関連記事

[aws-cli　コマンド一覧(随時追記)](http://qiita.com/bakira/items/8a9481c99ed56a367415)

# やりたかったこと

- SSL証明書発行時のドメイン認証メールをSESにて受信
- 受信メールをS3バケットに保存
- ~~GUIを使わずに黒い画面でコマンドを「**ッターーン!**」してかっこつけたい~~

# やったこと

## 前提

- CIサーバー(`ansible`実行サーバー)構築済み
- CLIサーバー(`aws-cli`実行サーバー)構築済み
- `Ansible`インストール済み
- `aws-cli`インストール済み
- 各サーバーへのSSH接続設定済み
- 独自ドメイン取得済み
- Route53の設定済み

※ `${~}`は各環境に合わせて値を設定してください。

## 作業フロー

### 1.　ドメイン認証用のトークンを発行

```bash:command
ansible-playbook -i inventory/production create-aws-ses-token.yml
```
**※戻り値の値を控えます**

### 2.　Route53のレコードセットの更新

```bash:command
ansible-playbook -i inventory/production update-aws-route53-record-set.yml
```

### 3.　Route53の承認ステータスの確認

```bash:command
ansible-playbook -i inventory/production view-aws-ses-verification-status.yml
```

VerificationStatusがSuccessになることを確認します。
<font color="red">※多少時間がかかる場合があります</font>

### ４.　メール保存用のS3バケットを作成

```bash:command
ansible-playbook -i inventory/production setup-aws-s3-bucket.yml
```

### 5.　SESルール周りのセットアップの作成

```bash:command
ansible-playbook -i inventory/production setup-aws-ses-rule.yml
```

## ディレクトリ構成
```text

├── ansible.cfg
├── create-aws-ses-token.yml
├── templates
│   └── production
│       ├── route53
│       │   └── record_set.j2
│       ├── s3api
│       │   └── s3-policy.j2
│       └── ses
│           └── rule-set.j2
├── inventory
│   └── production
│       └── inventory
├── roles
│   ├── active-aws-ses-rule-set
│   │   └── tasks
│   │       └── main.yml
│   ├── create-aws-s3-bucket
│   │   └── tasks
│   │       └── main.yml
│   ├── create-aws-ses-rule
│   │   └── tasks
│   │       └── main.yml
│   ├── create-aws-ses-rule-set
│   │   └── tasks
│   │       └── main.yml
│   ├── create-aws-ses-token
│   │   └── tasks
│   │       └── main.yml
│   ├── setup-aws-s3-bucket
│   │   └── tasks
│   │       └── main.yml
│   ├── update-aws-route53-record-set
│   │   └── tasks
│   │       └── main.yml
│   └── view-aws-ses-verification-status
│       └── tasks
│           └── main.yml
├── setup-aws-ses-rule.yml
├── setup-aws-s3-bucket.yml
├── update-aws-route53-record-set.yml
├── view-aws-ses-verification-status.yml
└── vars
    └── all.yml
```

## Ansible構成ファイル

### inventory

```ini:inventory/production/inventory
[ciservers]
${CIサーバーホスト}

[cliservers]
${CLIサーバーホスト}

[all:vars]
ENV=production

```

### vars

```yaml:vars/all.yml
SERVER_IP: ${IPアドレス}
TEMP:
  DIRECTORY: /temp
DOMAIN:
  MAIN:
    NAME: ${ドメイン名}
  SUB:
    NAME: ${サブドメイン名}
AWS:
  ROUTE53:
    HOSTED_ZONE_ID: ${ホストゾーンID}
  S3:
    BUCKET:
      NAME: ${バケット名}
  SES:
　　　　  TOKEN: ${認証トークン}
　　　　  REGION: us-west-2
    RULE:
      NAME: ${ルール名}
      SET:
        NAME: ${ルールセット名}
```

### templates

```json/production/ses/rule-set.j2
{
  "Name": "{{ AWS.SES.RULE.NAME }}",
  "Enabled": true,
  "TlsPolicy": "Optional",
  "Recipients": [
    "admin@{{ DOMAIN.MAIN.NAME }}",
    "admin@{{ DOMAIN.SUB.NAME }}"
  ],
  "Actions": [
    {
      "S3Action": {
        "BucketName": "{{ AWS.S3.BUCKET.NAME }}"
        }
    }
  ],
  "ScanEnabled": true
}
```

```json:s3-policy.j2
{
  "Version":"2012-10-17",
  "Statement":[{
      "Sid":"AddPerm",
      "Effect":"Allow",
        "Principal": "*",
      "Action":["s3:PutObject"],
      "Resource":["arn:aws:s3:::{{ AWS.S3.SES.NAME }}/*"]
    }
  ]
}
```


```json:record_set
{
  "Comment": "DomainRecords",
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "AliasTarget": {
          "HostedZoneId": "Z2FDTNDATAQYW2",
          "EvaluateTargetHealth": false,
          "DNSName": "{{ DOMAIN.MAIN.NAME }}"
        },
        "Type": "A",
        "Name": "{{ DOMAIN.MAIN.NAME }}"
      }
    },
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "{{ DOMAIN.SUB.NAME }}",
        "Type": "A",
        "TTL": 1200,
        "ResourceRecords": [
          {
            "Value": "{{ SERVER_IP }}"
          }
        ]
      }
    },
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "_amazonses.{{ DOMAIN.MAIN.NAME }}.",
        "Type": "TXT",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "\"{{ AWS.SES.TOKEN }}\""
          }
        ]
      }
    },
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "{{ DOMAIN.MAIN.NAME }}.",
        "Type": "MX",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "10 inbound-smtp.{{ AWS.SES.REGION }}.amazonaws.com."
          }
        ]
      }
    }
  ]
}
```


### playbook

```yaml:create-aws-ses-token.yml
- hosts: cliservers
  roles:
    - create-aws-ses-token
  vars_files:
    - vars/all.yml
```

```yaml:setup-aws-ses-rule.yml
- hosts: cliservers
  roles:
    - create-aws-ses-rule-set
    - create-aws-ses-rule
    - active-aws-ses-rule-set
  vars_files:
    - vars/all.yml
```

```yaml:setup-aws-s3-bucket.yml
- hosts: cliservers
  roles:
    - create-aws-s3-bucket
    - setup-aws-s3-bucket
  vars_files:
    - vars/all.yml
```

```yaml:update-aws-route53-record-set.yml
- hosts: cliservers
  roles:
    - update-aws-route53-record-set
  vars_files:
    - vars/all.yml
```

```yaml:view-aws-ses-verification-status.yml
- hosts: cliservers
  roles:
    - view-aws-ses-verification-status
  vars_files:
    - vars/all.yml
```

### tasks

```yaml:role/active-aws-ses-rule-set/tasks/main.yml
- name: Active Receipt Rule Set
  shell: |
    aws ses set-active-receipt-rule-set \
    --region={{ AWS.SES.REGION }} \
    --rule-set-name {{ AWS.SES.RULE.SET.NAME }}
  register: result
  changed_when: False

- debug: var=result.stdout_lines
  when: result | success
  tags:
    - always
```

```yaml:role/create-aws-s3-bucket/tasks/main.yml
- name: Create Bucket
  shell: "aws s3 mb s3://{{ AWS.S3.BUCKET.NAME }}"
  register: result
  changed_when: False

- debug: var=result.stdout_lines
  when: result | success
  tags:
    - always
```

```yaml:role/create-aws-ses-rule-set/tasks/main.yml
- name: Create Receipt Rule Set
  shell: |
    aws ses create-receipt-rule-set \
    --region={{ AWS.SES.REGION }} \
    --rule-set-name {{ AWS.SES.RULE.SET.NAME }} 
  register: result
  changed_when: False

- debug: var=result.stdout_lines
  when: result | success
  tags:
    - always
```

```yaml:role/create-aws-ses-rule/tasks/main.yml
- name: Create Replaced File
  template: 
    src={{ ENV }}/ses/rule-set.j2
    dest={{ TEMP.DIRECTORY }}/rule-set.json
  tags:
    - always

- name: Create Receipt Rule
  shell: |
    aws ses create-receipt-rule \
    --region={{ AWS.SES.REGION }} \
    --rule-set-name {{ AWS.SES.RULE.SET.NAME }} \
    --rule file://{{ TEMP.DIRECTORY }}/rule-set.json
  register: result
  changed_when: False

- debug: var=result.stdout_lines
  when: result | success
  tags:
    - always
```

```yaml:role/create-aws-ses-token/tasks/main.yml
- name: "Create SES Token"
  shell: |
    aws ses verify-domain-identity  \
    --domain "{{ DOMAIN.MAIN.NAME }}" \
    --region={{ AWS.SES.REGION }}
  register: result
  changed_when: False

- debug: var=result.stdout_lines
  when: result | success
  tags:
    - always
```

```yaml:role/setup-aws-s3-bucket/tasks/main.yml
- name: Create Replaced File
  template: 
    src={{ ENV }}/s3api/s3-policy.j2
    dest={{ TEMP.DIRECTORY }}/s3-policy.json
  tags:
    - always

- name: Create Policy
  shell: |
    aws s3api put-bucket-policy \
    --bucket {{ AWS.S3.BUCKET.NAME }} \
    --policy file://{{ TEMP.DIRECTORY }}/s3-policy.json
  register: result
  changed_when: False

- debug: var=result.stdout_lines
  when: result | success
  tags:
    - always
```

```yaml:role/update-aws-route53-record-set/tasks/main.yml
- name: Create Replaced File
  template: 
    src={{ ENV }}/route53/record_set.j2
    dest={{ TEMP.DIRECTORY }}/record_set.json
  tags:
    - always

- name: Update Record Set
  shell: |
    aws route53 change-resource-record-sets \
    --hosted-zone-id {{ AWS.ROUTE53.HOSTED_ZONE_ID }} \
    --change-batch file://{{ TEMP.DIRECTORY }}/record_set.json
  register: result
  changed_when: False

- debug: var=result.stdout_lines
  when: result | success
  tags:
    - always
```

```yaml:role/view-aws-ses-verification-status/tasks/main.yml
- name: View Verification Status
  shell: |
    aws ses get-identity-verification-attributes \
    --identities ${DOMAIN.MAIN.NAME}
  register: result
  changed_when: False

- debug: var=result.stdout_lines
  when: result | success
  tags:
    - always
```

## 終わりに

上記作業が正常に終了すれば、`SSL`証明書発行時のドメイン認証メールを`SES`にて受信及び`S3`バケットへの保存が可能になりました。

ただ、`S3`バケット上で保存している電子メールは **そのままだと解読が出来ない** ので、オブジェクトをローカル等にダウンロードした上で内容を表示する必要があります。(`Lambda`を使えば転送とかもできるかも？)

ここまでの設定をすれば`ACM`にて無料の`SSL`証明書を発行する準備が出来たので、
 **`CloudFront`+`S3`+`ACM`による無料`SSL`サイトを構築することが可能** です。

`AWS`サービス同士はとても連携しやすく、同サービス内だからこそのメリットもたくさんあるので他にも良い組み合わせがあったら記事にまとめていこうと思います♪

じゃあの。