httpdパッケージでApacheをインストール・HTTPS対応し、Let's Encryptの証明書の発行と設定までAnsibleで設定、できるのかな?と思って試したらうまくいった。
Let's Encryptで証明書を作成するには、ACMEプロトコルを利用し、このACMEプロトコルを操作するためのacme_certificateモジュールがAnsibleには(バージョン2.10ではcommunity.cryptoコレクションに)用意されている。
証明書発行部分は外部からのHTTPアクセスに対応できれば良いので、特にApacheである必要はなくNginxでも何でもよい。
環境
- コントロールノード
(a2.10) [zaki@cloud-dev acme (master)]$ cat /etc/centos-release CentOS Linux release 7.9.2009 (Core) (a2.10) [zaki@cloud-dev acme (master)]$ ansible --version ansible 2.10.2 config file = /home/zaki/src/ansible-sample/acme/ansible.cfg configured module search path = ['/home/zaki/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /home/zaki/src/ansible-sample/venv/a2.10/lib64/python3.6/site-packages/ansible executable location = /home/zaki/src/ansible-sample/venv/a2.10/bin/ansible python version = 3.6.8 (default, Nov 16 2020, 16:55:22) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
- ターゲットノード(webサーバー)
[root@instance-20200127-2223 ~]# cat /etc/oracle-release Oracle Linux Server release 7.9
ドメインは別途設定。
ターゲットノードはOracle CloudのAlways Free枠のインスタンス。
グローバルIPとAレコードを設定したFQDNがあれば仕組み的に特に環境は問わない。
外部からの80/TCP
と443/TCP
は全許可。
(証明書発行が済んだら制限して良い)
内容はRPM系のLinux OSになってるので、APT系の場合はコマンドやパスが異なる場合は読み替えること。
playbook
実際に動作確認したものをGitHubにあげていますので急いでる方はこちらをどうぞ。
流れ
基本的な流れはacme_certificateモジュールのExamplesを見れば良かった。
httpdのインストールとHTTPS対応
Yum系のLinuxの場合は、mod_ssl
パッケージを入れればlocalhost用証明書付きで/etc/httpd/conf.d/ssl.conf
と/etc/httpd/conf.modules.d/00-ssl.conf
も作成される。
証明書がダミーという点を除いて、起動すれば443/TCPでListenする。
なおapache2_moduleモジュールも存在するが、このモジュールで必要なa2enmod
はAPT系でapache2をインストールすると付属するが、Yumのhttpdには含まれてなかった。
Let's Encryptで証明書発行
ExamplesとPlaybookを見た方が早いですが、大まかな流れは以下の通り。
- Let's Encrypt用のアカウントキーを作成
- サーバー証明書の秘密鍵を作成
- サーバー証明書の秘密鍵から証明書署名要求(CSR)を作成
- 38-42行目
- openssl_csrモジュール使用
- ここでFQDNを指定する
- 作成したアカウントキーとCSRでLet's EncryptにACMEのチャレンジ要求
- 44-56行目
- acme_certificateモジュールを使用
- account_email は必須ではないように見えるけど未確認。期限切れ近くになると通知してくれるらしい。
- acme_certificateはデフォルトではACMEv1で動作するが、Let's Encryptではv1はすでに廃止されており403エラーとなる。
acme_version
で2
を指定し、明示的にACMEv2を設定- それだけだと
urn:ietf:params:acme:error:malformed
,must agree to terms of service
というエラーが発生したためterms_agreed: true
も追加で設定 - End of Life Plan for ACMEv1 - API Announcements - Let's Encrypt Community Support
- チャレンジ要求のレスポンスの内容でトークンファイルをwebサーバー上に作成
- チャレンジの検証を要求し、証明書を取得する
- 73-81行目
- パラメタはチャレンジ要求時とほぼ同じだが
data
に最初のレスポンス内容を追加している
- webサーバーで鍵のパスを設定する
要点
- acme_certificateモジュールのExamplesをよく見る
- チャレンジの過程でLet's EncryptからのHTTPアクセスを要するのでアクセス許可が必要 (アクセス元アドレスは公開されてなさそうなので
0.0.0.0/0
を許可した。実際は複数の箇所からアクセスがあった)- なおこれはHTTP-01チャレンジの場合。他にDNSなどの方式がある
- チャレンジのタイプ - Let's Encrypt - フリーな SSL/TLS 証明書
- acme_certificateモジュールはデフォルトでACMEv1を使用するがLet's EncryptではACMEv2での操作が必要
- モジュールの
Requirements
で要求されているcryptography
などを入れてlibselinux-python3
も入れてるのにtarget uses selinux but Python bindings (libselinux-Python) aren't installed
と出たらpip install selinux
- ※ 「更新」はまだ試してない