Let's EncryptをCentOS7のApacheに設定する(Ansibleの設定もあり)

## 概要
表題のとおり。

## 環境
- CentsOS7.4
- Apache/2.4.6

## 事前準備
Let's Encryptの設定をするにあたって、**<font color="crimson">対象のドメインでwebサーバーにアクセスできる状態</font>**である必要があります。

つまり、設定の手順を簡単に説明すると、以下になります。

1. webサーバーを構築し起動する
2. 対象のドメインでwebページへアクセス可能な状態にする
    - 公開ディレクトリさえ存在していれば、ディレクトリの中は空でもOK
3. `certbot`コマンドで証明書を取得する
4. webサーバーで証明書を読み込ませる設定をする


以下の手順では、1,2は完了していることを前提とします。

## certbotのインストール
CentOS7へインストールする。

```
$ sudo yum install epel-release
$ sudo yum install certbot python-certbot-apache
```

https://letsencrypt.jp/usage/install-certbot.html#CentOS7

## certbotコマンド実行時のhookを設定
certbot実行時に、httpdのrestartが実行されるようにします。

```
$ sudo sed -i /etc/sysconfig/certbot \
 -e "/^PRE_HOOK/ s/\"\"/\"--pre-hook 'systemctl stop httpd'\"/" \
 -e "/^POST_HOOK/ s/\"\"/\"--post-hook 'systemctl restart httpd'\"/" \
 -e "/^RENEW_HOOK/ s/\"\"/\"--renew-hook 'systemctl restart httpd'\"/"
```

## certbotコマンドで証明書を取得する
以下のコマンドを実行する

```
$ sudo certbot certonly --email example@example.com  \
    --agree-tos \
    --non-interactive $* \
    --webroot \
    -w /var/www/html/example_app/public \
    -d www.example.com

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None
Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for www.example.com
Using the webroot path /var/www/html/example_app/public for all unmatched domains.
Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/www.example.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/www.example.com/privkey.pem
   Your cert will expire on 2018-06-22. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le
```

以下のファイルが生成される

```
$ sudo ls -l /etc/letsencrypt/live/www.example.com/
合計 4
-rw-r--r-- 1 root root 543  3月 24 14:33 README
lrwxrwxrwx 1 root root  44  3月 24 14:33 cert.pem -> ../../archive/www.example.com/cert1.pem
lrwxrwxrwx 1 root root  45  3月 24 14:33 chain.pem -> ../../archive/www.example.com/chain1.pem
lrwxrwxrwx 1 root root  49  3月 24 14:33 fullchain.pem -> ../../archive/www.example.com/fullchain1.pem
lrwxrwxrwx 1 root root  47  3月 24 14:33 privkey.pem -> ../../archive/www.example.com/privkey1.pem
```

## Apacheの設定
Apacheのconfで、以下のように設定する。

以下は、Apache/2.4.8以前の場合の設定。
SSLCertificateFileは、Apache/2.4.8以降や、nginxでは使用しません。

```conf
    SSLEngine on
    SSLProtocol all -SSLv2
    SSLCertificateKeyFile   /etc/letsencrypt/live/www.example.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/www.example.com/chain.pem
    SSLCertificateFile      /etc/letsencrypt/live/www.example.com/fullchain.pem
```

- 参考
    - [7. SSL/TLS サーバ証明書の取得完了](https://letsencrypt.jp/usage/)
    - [CentOS6 or 7 + Apache2系のインストール手順](https://qiita.com/Esfahan/items/364462502b6d19dea1fe#http%E3%81%B8%E3%81%AE%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%82%92%E3%81%99%E3%81%B9%E3%81%A6https%E3%81%AB%E3%83%AA%E3%83%80%E3%82%A4%E3%83%AC%E3%82%AF%E3%83%88%E3%81%99%E3%82%8B%E8%A8%AD%E5%AE%9A)


## 更新

dry-run

```
$ certbot certonly \
    --dry-run \
    --force-renew \
    --webroot \
    -w /var/www/html/appname/public \
    -d sample.com \
    --post-hook 'systemctl reload httpd'
```

renew

```
$ certbot certonly \
    --force-renew \
    --webroot \
    -w /var/www/html/appname/public \
    -d sample.com \
    --post-hook 'systemctl reload httpd'
```

cronに設定することで、定期的に更新されるようになる

## Ansible
Ansibleで設定する場合

```yaml
---
- name: Install certbot,certbot-apache
  yum: name=certbot,certbot-apache state=present

- name: Install python-certbot-apache
  yum: name=python-certbot-apache state=present

- name: Set config to stop and restart with running certbot
  become: yes
  replace:
    dest: /etc/sysconfig/certbot
    regexp: "{{ item.regexp }}"
    replace: "{{ item.replace }}"
    backup: yes
  with_items:
    - {'regexp' : '^PRE_HOOK=""$', 'replace' : 'PRE_HOOK="--pre-hook ''systemctl stop httpd''"'}
    - {'regexp' : '^POST_HOOK=""$', 'replace' : 'POST_HOOK="--post-hook ''systemctl restart httpd''"'}
    - {'regexp' : '^RENEW_HOOK=""$', 'replace' : 'RENEW_HOOK="--renew-hook ''systemctl restart httpd''"'}

- name: Check privkey.pem exists
  stat: path=/etc/letsencrypt/live/{{ httpd.domain }}/privkey.pem
  register: fm

- name: Get certs
  become: yes
  shell: |
    certbot certonly -m {{ lets_encrypt.email }} --agree-tos --non-interactive $* --webroot -w {{ httpd.document_root }} -d {{ httpd.domain }}
  when: not fm.stat.exists

# 毎日AM4:00に更新を実行する
- name: Set cron to renew certs
  become: yes
  cron:
    name: Set cron to renew certs
    minute: "0"
    hour: "4"
    day: "*"
    month: "*"
    weekday: "*"
    job: |
      /bin/bash -lc "certbot certonly --force-renew --webroot -w {{ httpd.document_root }} -d {{ httpd.domain }} --post-hook 'systemctl reload httpd' > /dev/null 2>&1"
    state: present
```

## 参考
- [Let's Encrypt の使い方](https://letsencrypt.jp/usage/)
- [Let's encrypt運用のベストプラクティス](https://qiita.com/tkykmw/items/9b6ba55bb2a6a5d90963)
- [CentOS 7 の Apache に Let's Encrypt で SSL を設定する](https://qiita.com/bezeklik/items/3d664b29c99079a6b096)