Let's Encryptを証明書取得から証明書更新cron設定まで一気に設定するAnsible Role

Let's Encrypt活用していますか？

まだ導入に踏み切れていない人もいると思います。

[とても素晴らしいサイト](https://letsencrypt.jp/)あるのですが、いかんせんいままでの証明書のライフサイクルと違うところがあるため、最初は難しかったりします。

なので、今回は開発環境などで使っているAnsible Roleを紹介します。CentOS7想定です。

なお、説明に不必要な部分は省略しているので、もし動かなかったら適宜修正してください。

## roles/apache24-letsencrypt/task/main.yml

```yaml
---
- name: httpd2.4をインストール
  yum: name={{ item }} enablerepo=centos-sclo-rh state=present
  with_items:
    - httpd24-httpd
    - httpd24-httpd-devel
    - httpd24-mod_ssl

- name: docrootを作成
  file: path={{ docroot }} state=directory owner={{ username }} group={{ username }}

- name: httpd.confの設定
  template: src=httpd.conf.j2 dest=/opt/rh/httpd24/root/etc/httpd/conf/httpd.conf owner=root group=root mode=0644
  notify: restart httpd

- name: certbotをインストール
  yum: name=certbot state=latest enablerepo=epel

- name: httpd / firewalldを停止
  service: name={{ item }} state=stopped
  with_items:
    - httpd24-httpd
    - firewalld

- name: 証明書ファイルの存在チェック
  stat: path=/etc/letsencrypt/live/{{ hostname }}/cert.pem
  register: cert_file

- name: 証明書を作成
  command: certbot certonly --standalone -d {{ hostname }} --agree-tos --renew-by-default -m server@fusic.co.jp
  when: not cert_file.stat.exists

- name: virtualhosts.confを更新
  template: src=virtualhosts.conf.j2 dest=/opt/rh/httpd24/root/etc/httpd/conf.d/virtualhosts.conf owner=root group=root

- name: httpd / firewalldをスタート
  service: name={{ item }} state=started
  with_items:
    - httpd24-httpd
    - firewalld

- name: 証明書更新用cronを設置
  cron:
    name="renew-cert"
　  month="1,3,5,7,9,11"
    minute="0"
    hour="4"
    day="1"
    job='/usr/bin/systemctl stop httpd24-httpd.service && /usr/bin/certbot renew --force-renew --quiet --post-hook "/usr/bin/systemctl start httpd24-httpd.service"'
    user=root
    cron_file=renew_cert  

- name: httpdの起動設定
  service: name=httpd24-httpd enabled=yes state=started

- name: httpd2.4をパスに追加
  copy: src=enable_httpd24.sh dest=/etc/profile.d/enable_httpd24.sh mode=0644
```

## 解説

ポイントを解説します。

```yaml
- name: certbotをインストール
  yum: name=certbot state=latest enablerepo=epel
```

certbotは実はEPELでインストールできるのでそれに任せます

```yaml
- name: httpd / firewalldを停止
  service: name={{ item }} state=stopped
  with_items:
    - httpd24-httpd
    - firewalld
```

認証に80番ポートと443ポートを利用するので一旦httpdを止めます

```yaml
- name: 証明書ファイルの存在チェック
  stat: path=/etc/letsencrypt/live/{{ hostname }}/cert.pem
  register: cert_file

- name: 証明書を作成
  command: certbot certonly --standalone -d {{ hostname }} --agree-tos --renew-by-default -m server@fusic.co.jp
  when: not cert_file.stat.exists
```

最初の1回だけ行う証明書の取得処理です。

コマンドで規約の承認までしてしまっているので、事前に読んでおきましょう。

```yaml
- name: virtualhosts.confを更新
  template: src=virtualhosts.conf.j2 dest=/opt/rh/httpd24/root/etc/httpd/conf.d/virtualhosts.conf owner=root group=root

- name: httpd / firewalldをスタート
  service: name={{ item }} state=started
  with_items:
    - httpd24-httpd
    - firewalld
```

証明書を利用する形にconfを書き換えてhttpd / firewalldを起動します。

ちなみに roles/apache24-letsencrypt/templates/virtualhosts.conf.j2 は以下のような感じです

```
Listen 443 https
SSLCryptoDevice builtin
SSLPassPhraseDialog builtin
SSLRandomSeed connect builtin
SSLRandomSeed startup file:/dev/urandom 256
SSLSessionCache shmcb:/opt/rh/httpd24/root/var/run/httpd/sslcache(512000)
SSLSessionCacheTimeout 300

<VirtualHost _default_:443>
  DocumentRoot {{ docroot }}
  ServerName {{ hostname }}
  <Directory {{ docroot }}>
    AllowOverride All
    DirectoryIndex index.html index.htm index.php
    Options FollowSymLinks
    Require all granted
  </Directory>

  ErrorLog logs/ssl_error_log
  TransferLog logs/ssl_access_log
  LogLevel warn
  SSLEngine on
  SSLProtocol all -SSLv2 -SSLv3
  SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW

  #   Server Certificate:
  SSLCertificateFile /etc/letsencrypt/live/{{ hostname }}/cert.pem

  #   Server Private Key:
  SSLCertificateKeyFile /etc/letsencrypt/live/{{ hostname }}/privkey.pem

  #   Server Certificate Chain:
  SSLCertificateChainFile /etc/letsencrypt/live/{{ hostname }}/chain.pem

  SetEnvIf User-Agent ".*MSIE.*" \
    nokeepalive ssl-unclean-shutdown \
    downgrade-1.0 force-response-1.0
  CustomLog logs/ssl_request_log \
    "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
</VirtualHost>
```

```yaml
- name: 証明書更新用cronを設置
  cron:
    name="renew-cert"
　  month="1,3,5,7,9,11"
    minute="4"
    hour="4"
    day="4"
    job='/usr/bin/systemctl stop httpd24-httpd.service && /usr/bin/certbot renew --force-renew --quiet --post-hook "/usr/bin/systemctl start httpd24-httpd.service"'
    user=root
    cron_file=renew_cert  
```

Let's Encryptの証明書は90日で失効するので、都度更新をする必要があります。60日1回更新することが推奨らしいので適当に深夜に更新するcronを設定します。

更新の際も80ポートと443ポートを利用するのでhttpdを停止するので注意が必要です。

DNSによる認証(DNS-01)でHTTPを使わずに認証もできるのですが、今回は開発環境なので割愛。

## というわけで

Let's Encrypt!!! （みんな言いたかったヤツ