Ansible の 2.2 から LetsEncrypt からサーバー証明書を取得するモジュール letsencrypt が追加されたので、実際に使用してみました。
YAML ファイル
配置構造は以下のようにしています。
実行対象は ubuntu 16.04 を想定しています。
├── inventories
│ └── web
├── letsencrypt.yaml
└── templates
├── letsencrypt.conf.j2
└── web.conf.j2
インベントリーファイル
web
[web]
web ansible_ssh_host=IPアドレスをここに
タスク
letsencrypt.yaml
- hosts: web
serial: 1
remote_user: ubuntu
become: yes
tasks:
- name: パッケージインストール
apt: name={{ item }} state=installed
with_items:
- nginx
- openssl
- python-openssl
# LetsEncrypt向けの nginx の準備
- name: default設定ファイルを削除する
file: path="/etc/nginx/sites-enabled/default" state=absent
- name: LetsEncrypt用の nginx の設定ファイルを配置する
template: src="letsencrypt.conf.j2" dest="/etc/nginx/sites-available/letsencrypt.conf"
- name: LetsEncrypt用の nginx の設定ファイルをリンクする
file: src="/etc/nginx/sites-available/letsencrypt.conf" dest="/etc/nginx/sites-enabled/letsencrypt.conf" state=link
- name: nginx を reload
service: name=nginx state=reloaded
# ディレクトリの準備
- name: letsencrypt ACMEチャレンジ用ディレクトリを作成する
file: path=/var/www/letsencrypt/.well-known/acme-challenge state=directory owner="{{ username }}" group="{{ username }}"
- name: サーバー証明書用のディレクトリを作成する
file: path=/etc/ssl/{{ domain }} state=directory
# 鍵の準備
- name: LetsEncrypt のアカウント鍵を生成する
openssl_privatekey: path=/etc/ssl/{{ domain }}/account.key
- name: サーバー証明書の秘密鍵を作成する
openssl_privatekey: path=/etc/ssl/{{ domain }}/domain.key
- name: サーバー証明書の署名要求ファイルを作成する
command: openssl req -new -key domain.key -out {{ domain }}.csr -subj "/C=JP/ST=Tokyo/L=Tokyo/O=zenwerk/CN={{ domain }}" chdir=/etc/ssl/{{ domain }} creates={{ domain }}.csr
# 証明書を取得する
- name: LetsEncrypt にチャレンジ要求を行う
letsencrypt:
acme_directory: https://acme-v01.api.letsencrypt.org/directory
account_key: /etc/ssl/{{ domain }}/account.key
csr: /etc/ssl/{{ domain }}/{{ domain }}.csr
dest: /etc/ssl/{{ domain }}/cert.pem
remaining_days: 90
register: acme_challenge
- name: LetsEncrypt のチャレンジ要求を設定する
become: no
copy:
dest: /var/www/letsencrypt/{{ acme_challenge['challenge_data'][domain]['http-01']['resource'] }}
content: "{{ acme_challenge['challenge_data'][domain]['http-01']['resource_value'] }}"
when: acme_challenge|changed
- name: LetsEncrypt のチャレンジを実施し証明書を取得する
letsencrypt:
acme_directory: https://acme-v01.api.letsencrypt.org/directory
account_key: /etc/ssl/{{ domain }}/account.key
csr: /etc/ssl/{{ domain }}/{{ domain }}.csr
dest: /etc/ssl/{{ domain }}/cert.pem
remaining_days: 90
data: "{{ acme_challenge }}"
# 中間証明書の準備
- name: LetsEncrypt の中間証明書を取得する
get_url:
url: "{{ letsencrypt_intermidiate_ca }}"
dest: /etc/ssl/{{ domain }}/chain.pem
- name: 中間証明書を作成する
shell: cat cert.pem chain.pem > fullchain.pem chdir=/etc/ssl/{{ domain }}
# コンテンツ配信向けの nginx の準備
- name: コンテンツ配信用の nginx の設定ファイルを配置する
template: src="web.conf.j2" dest="/etc/nginx/sites-available/web.conf"
- name: コンテンツ配信用の nginx の設定ファイルをリンクする
file: src="/etc/nginx/sites-available/web.conf" dest="/etc/nginx/sites-enabled/web.conf" state=link
notify: reload nginx
handlers:
- name: reload nginx
service: name=nginx state=reloaded
vars:
username: ubuntu
domain: 設定したいドメイン名をここに
letsencrypt_intermidiate_ca: https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem.txt
必要な設定ファイル
Webサーバは nginx を対象にしました
letsencrypt.conf
server {
listen 80;
client_max_body_size 20M;
server_name {{ domain }};
location /.well-known/acme-challenge/ {
alias /var/www/letsencrypt/.well-known/acme-challenge/;
try_files $uri =404;
access_log off;
}
location / {
rewrite ^(.*)$ https://{{ domain }}$1 permanent;
}
}
web.conf
server {
listen 443 ssl;
client_max_body_size 20M;
server_name {{ domain }};
ssl_certificate /etc/ssl/{{ domain }}/fullchain.pem;
ssl_certificate_key /etc/ssl/{{ domain }}/domain.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
index index.html index.htm index.nginx-debian.html;
root /var/www/html/;
location / {
try_files $uri $uri/ =404;
}
}
実行
ansible-playbook -i inventories/web letsencrypt.yaml
課題
- LetsEncrypt の証明書は3ヶ月ごとに更新する必要がある
- 定期的に playbook を実行する仕組みが必要になる
- リモート側で
cert-bot renew
などを cron するほうが楽
- preview のモジュールなので、将来仕様が変わる可能性がある
感想
- ある程度自動化してくれるが ACMEチャレンジを実行できる環境を設定する必要があり、cert-bot よりは面倒
- 中間証明書なども自分で作成する必要がある
- 何らかの理由で cert-bot などの ACMEプロトコルを実行してくれるクライアントを使用できない場合は便利かもしれない