1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Let'sEncrypt+certbotでSSL証明書を作る

Last updated at Posted at 2020-04-29

目標

  • Let'sEncryptで以下の4種類のSSL証明書を作る
    • シングルドメイン
    • マルチドメイン(SANs):同じコンテンツ
    • マルチドメイン(SANs):異なるコンテンツ
    • ワイルドカード
  • 証明書の自動更新もできるようにする

環境

  • サーバOS
    • CentOS7
  • Webサーバ
    • apache2.4 + mod_ssl
  • ワイルドカード証明書のDNS-01認証に使うDNSサーバ
    • さくらのクラウド

準備

certbotをインストールする

yum -y install certbot

epelが未インストールの場合は事前にインストールする必要がある
certbotのバージョンは1.3.0

[root@localhost ~] certbot --version
certbot 1.3.0

シングルドメイン証明書

ドメインとDocumentRoot

ドメインmydomain.foobarはもちろん架空

ドメイン DocumentRoot
ssl.mydomain.foobar /var/www/html.ssl
# SSL化前のApacheの設定
<VirtualHost *:80>
  ServerName  ssl.mydomain.foobar
  DocumentRoot /var/www/html.ssl
</VirtualHost>

証明書作成

certbot certonly \
--webroot -w /var/www/html.ssl -d ssl.mydomain.foobar \
-m <メールアドレス> --no-eff-email \
--agree-tos --manual-public-ip-logging-ok
certonly
証明書の作成を行う(インストールはしない)
--webroot
ドメイン認証にHTTP-01を使う
-w /var/www/html.ssl
DocumentRootの指定
-d ssl.mydomain.foobar
SSL証明書の対象のドメイン
-m <メールアドレス>
メールアドレスを登録する。このアドレスに更新案内等のメールが配信される
--no-eff-email
EFF(Let'sEncryptのスポンサー団体)からのDMを許可しない。
許可する場合は代わりに --eff-email を指定する。
どちらも指定しなければ、処理中に入力を求められる。
--agree-tos
規約に承認する。
ここで指定しておかないと、処理中に入力を求められる。
--manual-public-ip-logging-ok
実行中のサーバのIPアドレスを記録しても構わないという承認をする。
ここで指定しておかないと、処理中に入力を求められる。

作成された証明書

/etc/letsencrypt/live/ssl.mydomain.foobar/に下記のファイルが作られている

ファイル名 用途
cert.pem SSL証明書
chain.pem OSCP用中間証明書
fullchain.pem 非OSCP用中間証明書
privkey.pem 秘密鍵
# SSL対応のApacheの設定
<VirtualHost *:443>
    ServerName   ssl.mydomain.foobar
    DocumentRoot /var/www/html.ssl
    SSLEngine on
    ### 中略:SSLProtocolとかSSLCipherSuiteとか ###
    SSLCertificateFile      /etc/letsencrypt/live/ssl.mydomain.foobar/cert.pem
    SSLCertificateKeyFile   /etc/letsencrypt/live/ssl.mydomain.foobar/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/ssl.mydomain.foobar/fullchain.pem 
</VirtualHost>

マルチドメイン(SANs):同じコンテンツ

ドメインとDocumentRoot

ドメイン DocumentRoot
www.mydomain.foobar /var/www/html.www
mydomain.foobar /var/www/html.www
# SSL化前のApacheの設定
<VirtualHost *:80>
  ServerName      www.mydomain.foobar
  ServerAlias     mydomain.foobar
  DocumentRoot    /var/www/html.www
</VirtualHost>

証明書作成

certbot certonly 
--webroot -w /var/www/html.www -d www.mydomain.foobar -d mydomain.foobar \
-m <メールアドレス> --no-eff-email \
--agree-tos --manual-public-ip-logging-ok
-w /var/www/html.www
DocumentRootの指定
www.mydomain.foobarとmydomain.foobarで共通
-d www.mydomain.foobar -d mydomain.foobar
証明書を利用するドメインを列挙する

作成された証明書

/etc/letsencrypt/live/www.mydomain.foobar/にシングルドメインの場合と同じファイルが作られている

# SSL対応のApacheの設定
<VirtualHost *:443>
    ServerName   www.mydomain.foobar
    ServerAlias  mydomain.foobar
    DocumentRoot /var/www/html.www
    SSLEngine on
    ### 中略:SSLProtocolとかSSLCipherSuiteとか ###
    SSLCertificateFile      /etc/letsencrypt/live/www.mydomain.foobar/cert.pem
    SSLCertificateKeyFile   /etc/letsencrypt/live/www.mydomain.foobar/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/www.mydomain.foobar/fullchain.pem 
</VirtualHost>

マルチドメイン(SANs):異なるコンテンツ

ドメインとDocumentRoot

ドメイン DocumentRoot
san1.mydomain.foobar /var/www/html.san1
san2.mydomain.foobar /var/www/html.san2
san2.mydomain.foobar /var/www/html.san3
# SSL化前のApacheの設定
<VirtualHost *:80>
  ServerName      san1.mydomain.foobar
  DocumentRoot    /var/www/html.san1
</VirtualHost>
<VirtualHost *:80>
  ServerName      san2.mydomain.foobar
  DocumentRoot    /var/www/html.san2
</VirtualHost>
<VirtualHost *:80>
  ServerName      san3.mydomain.foobar
  DocumentRoot    /var/www/html.san3
</VirtualHost>

証明書作成

certbot certonly 
--webroot \
-w /var/www/html.san1 -d san1.mydomain.foobar \
-w /var/www/html.san2 -d san2.mydomain.foobar \
-w /var/www/html.san3 -d san3.mydomain.foobar \
-m <メールアドレス> --no-eff-email \
--agree-tos --manual-public-ip-logging-ok 

-w-dの順番が重要
ドメインとドキュメントルートの対応がわかるように、-w -dの順で正しい組み合わせで繰り返し記述する。

-w /var/www/html.san1 -d san1.mydomain.foobar
san1.mydomain.foobar の DocumentRoot は /var/www/html.san1
-w /var/www/html.san2 -d san2.mydomain.foobar
san2.mydomain.foobar の DocumentRoot は /var/www/html.san2
-w /var/www/html.san3 -d san2.mydomain.foobar
san2.mydomain.foobar の DocumentRoot は /var/www/html.san2

作成された証明書

/etc/letsencrypt/live/san1.mydomain.foobar/にシングルドメインの場合と同じファイルが作られている
最初の-dで指定したドメインがディレクトリ名に採用される

# SSL対応のApacheの設定
<VirtualHost *:443>
  ServerName      san1.mydomain.foobar
  DocumentRoot    /var/www/html.san1
  SSLEngine on
  ### 中略:SSLProtocolとかSSLCipherSuiteとか ###
  SSLCertificateFile      /etc/letsencrypt/live/san1.mydomain.foobar/cert.pem
  SSLCertificateKeyFile   /etc/letsencrypt/live/san1.mydomain.foobar/privkey.pem
  SSLCertificateChainFile /etc/letsencrypt/live/san1.mydomain.foobar/fullchain.pem 
</VirtualHost>
<VirtualHost *:443>
  ServerName      san2.mydomain.foobar
  DocumentRoot    /var/www/html.san2
  SSLEngine on
  ### 中略:SSLProtocolとかSSLCipherSuiteとか ###
  SSLCertificateFile      /etc/letsencrypt/live/san1.mydomain.foobar/cert.pem
  SSLCertificateKeyFile   /etc/letsencrypt/live/san1.mydomain.foobar/privkey.pem
  SSLCertificateChainFile /etc/letsencrypt/live/san1.mydomain.foobar/fullchain.pem 
</VirtualHost>
<VirtualHost *:443>
  ServerName      san3.mydomain.foobar
  DocumentRoot    /var/www/html.san3
  SSLEngine on
  ### 中略:SSLProtocolとかSSLCipherSuiteとか ###
  SSLCertificateFile      /etc/letsencrypt/live/san1.mydomain.foobar/cert.pem
  SSLCertificateKeyFile   /etc/letsencrypt/live/san1.mydomain.foobar/privkey.pem
  SSLCertificateChainFile /etc/letsencrypt/live/san1.mydomain.foobar/fullchain.pem 
</VirtualHost>

ワイルドカード

方針

  • *.mydomain.foobarのワイルドカード証明書を作る
  • ワイルドカードの場合はドメイン認証にHTTP-01は使えず、DNS-01で認証する。
  • DNS-01認証のために、mydomain.foobarのDNSで_acme-challenge.mydomain.foobarのTXTレコードを登録する必要がある。手作業で登録してもいいのだが、そうすると(おそらく)証明書更新が自動でできない。
    • 登録する値が毎回変わるため
  • 自動更新するためには、そのためのcertbotのプラグインを利用すればよい。プラグインは多数のDNSサーバに対応したものが提供されている。
  • mydomain.foobarのDNSはプラグインが対応していない。とは言え、DNSサーバ自体を移設するのは何かと大変でやりたくない。
  • サブドメイン_acme-challenge.mydomain.foobarをプラグイン対応しているDNSサーバに委譲する。プラグイン対応しているDNSサーバ側で、_acme-challenge.mydomain.foobarのTXTレコードのみを処理してもらうことにする。
  • 今回はプラグイン対応DNSサーバとしてさくらインターネットのさくらのクラウドを利用することにする。
    • さくらのクラウドのアカウントを元から持っていたことと、DNSサービス利用料が1ゾーン数十円/月のコストで済むことから決定した。
  • HTTP-01認証ではないので、証明書作成/更新時にhttp接続可能なWebサーバが起動していないくてもよい。

さくらクラウドの準備

  1. さくらクラウドのアカウントを作る(持っていない場合)
  2. DNSサービスにゾーンmydomain.foobarを追加作成する
  3. 作成したゾーンのDNSサーバホスト名(2つあるはず)をメモっておく。DNSゾーンの詳細情報ページに書いてある。
  4. さくらクラウドのAPIキーを作成する。作成したキーのアクセストークンアクセストークンシークレットをメモっておく。
  • 作成するゾーンは_acme-challenge.mydomain.foobarではなくmydomain.foobarにする、そうしないとプラグインがうまく動かない
  • ゾーンの作成だけでOK。レコードは必要ない。
  • mydomain.foobar自体のDNSをレジストラで変更してはいけない。元のDNSサーバが使えなくなって大惨事になる。

本来のDNSにレコード追加

mydomain.foobarのDNSを管理している本来のDNSサーバに下記のレコードを追加して、_acme-challenge.mydomain.foobarをさくらクラウドに委譲する。

_acme-challenge IN NS <さくらクラウドのDNSサーバ名1>
_acme-challenge IN NS <さくらクラウドのDNSサーバ名2>

プラグインのインストール

yum -y install python-certbot-dns-sakuracloud

プラグイン用の設定ファイルを用意

プラグインが使用する設定ファイルにさくらクラウドのAPIキー情報を書いて保存する。今回は/root/letsencrypt/sakura_api.confというファイル名にする。
設定ファイルのパーミッションは600にしないとプラグインがエラーを吐いて動作しない。

/root/letsencrypt/sakura_api.conf
dns_sakuracloud_api_token = "<さくらクラウドAPIキーのアクセストークン>"
dns_sakuracloud_api_secret = "<さくらクラウドAPIキーのアクセストークンシークレット>"

更新時もこのプラグインがこのファイルを読み込むので、うっかり削除してしまわないように、あまり適当な名前にしないほうがよいだろう。

証明書作成

certbot certonly \
--dns-sakuracloud --dns-sakuracloud-credentials /root/letsencrypt/sakura_api.conf \
-d *.mydomain.foobar \
-m <メールアドレス> --no-eff-email \
--agree-tos --manual-public-ip-logging-ok \
--dns-sakuracloud
DNS-01認証にさくらクラウドDNS用プラグインを使用する
--dns-sakuracloud-credentials /root/letsencrypt/sakura_api.conf
さくらクラウドDNS用プラグインの設定(APIキー情報)ファイルを指定
-d *.mydomain.foobar
*.mydomain.foobarのワイルドカード用SSL証明書を作る

作成された証明書

/etc/letsencrypt/live/mydomain.foobar/にシングルドメインの場合と同じファイルが作られている

# SSL対応のApacheの設定
<VirtualHost *:443>
  ServerName      host.mydomain.foobar
  DocumentRoot    /var/www/html.host1
  SSLEngine on
  ### 中略:SSLProtocolとかSSLCipherSuiteとか ###
  SSLCertificateFile      /etc/letsencrypt/live/mydomain.foobar/cert.pem
  SSLCertificateKeyFile   /etc/letsencrypt/live/mydomain.foobar/privkey.pem
  SSLCertificateChainFile /etc/letsencrypt/live/mydomain.foobar/fullchain.pem 
</VirtualHost>
<VirtualHost *:443>
  ServerName      another.mydomain.foobar
  DocumentRoot    /var/www/html.another
  ### 中略:SSLProtocolとかSSLCipherSuiteとか ###
  SSLCertificateFile      /etc/letsencrypt/live/mydomain.foobar/cert.pem
  SSLCertificateKeyFile   /etc/letsencrypt/live/mydomain.foobar/privkey.pem
  SSLCertificateChainFile /etc/letsencrypt/live/mydomain.foobar/fullchain.pem 
</VirtualHost>
<VirtualHost *:443>
  ServerName      any.mydomain.foobar
  DocumentRoot    /var/www/html.any
  ### 中略:SSLProtocolとかSSLCipherSuiteとか ###
  SSLCertificateFile      /etc/letsencrypt/live/mydomain.foobar/cert.pem
  SSLCertificateKeyFile   /etc/letsencrypt/live/mydomain.foobar/privkey.pem
  SSLCertificateChainFile /etc/letsencrypt/live/mydomain.foobar/fullchain.pem 
</VirtualHost>

課題

本来はさくらクラウドDNSにはmydomain.foobarではなく_acme-challenge.mydomain.foobarのゾーンを作成して運用したかった。
元のDNSから委譲しているのが_acme-challenge.mydomain.foobarなのに委譲される側のゾーンが不一致なのが気持ち悪いからである。
certbotのさくらクラウドDNS用プラグインで、そうした設定(作成する証明書のドメインとさくらクラウドDNSのゾーンが一致しない)で使用できない(多分)ので、仕方なく今回のような設定にしている。
そもそもRFC的にこの運用が許されるのかどうかも怪しいと思っている。⇒どなたかお教えください。
また、さくらDNSクラウドでゾーンを作成する時に次の注意文が表示される。

作成後表示される当社DNSサーバに対して、権限委譲をお願いします。
なお、1ヶ月以内に委譲がなされない場合、登録が削除されることがあります。

_acme-challenge.mydomain.foobarは委譲しているがmydomain.foobarは委譲していないので1ヶ月後にゾーン情報を削除されてしまうかもしれない。

自動更新

Let'sEncryptのSSL証明書は有効期限が3ヶ月と通常の有償のものと比べると短い。
そのため、自動更新できる仕組みを構築しておきたい。

手動で更新するのであれば、シェルから下記のコマンドを実行すればよい。

certbot renew

そのホストで作成したLet'sEncryptの証明書を全て更新できる。
ただし、有効期限が30日以上残っている証明書は更新されない。

上記コマンドで更新すると、新規作成時と同じ設定(HTTP-01認証やDNS-01認証など)で更新処理が行われる。
そのため、新規作成時とDocumentRootが変わっていたりDNS設定が変わっていたりすると更新に失敗するので注意が必要。

自動更新用のスクリプトを用意する。

/root/letsencrypt/renew.sh
# !/bin/bash

certbot renew
systemctl reload httpd.service

そのスクリプトをrootのcronで月2回実行する。頻度は運用に合わせて調整してほしい。

0 4 10,25 * * /root/letsencrypt/renew.sh

実際に更新がうまくできるたどうかは、3ヶ月後に追記します

HTTP-01認証のTips

httpsへのリダイレクト

http⇒httpsにリダイレクトしている場合、-wにはhttpsのDocumentRootを指定すればよい。
このとき、httpsの証明書が勝手証明書(mod_sslのデフォルト証明書とか)でも大丈夫。

# http接続をhttps接続にリダイレクト
<VirtualHost *:80>
  ServerName  www.mydomain.foobar
  Redirect    temp / https://www.mydomain.foobar/
</VirtualHost>

# https接続のSSL証明書と秘密鍵はmod_sslのデフォルトのもの
<VirutalHost *:443>
  ServerName   www.mydomain.foobar
  DocumentRoot /var/www/html.www
  SSLEngine on
  ### 中略:SSLProtocolとかSSLCipherSuiteとか ###
  SSLCertificateFile      /etc/pki/tls/certs/localhost.crt
  SSLCertificateKeyFile   /etc/pki/tls/private/localhost.key
</VirtualHost>
# 証明書作成コマンド
# DocumentRootはhttps://www.mydomain.foobar/のDocumentRoot
certbot certonly 
--webroot -w /var/www/html.www -d www.mydomain.foobar \
-m <メールアドレス> --no-eff-email \
--agree-tos --manual-public-ip-logging-ok

DocumentRootの変更

初回のSSL証明書作成時からDocumentRootを変更すると、更新時にHTTP-01認証が失敗する。
この場合は証明書を作り直してしまうか、一度ドキュメントルートを指定し直して手動更新するなどの対応が必要だと思われる。

BASIC認証を掛けている場合

httpアクセスしたとき(あるいは、そこからhttpsにリダイレクトしたとき)にBASIC認証が掛かっていると、SSL証明書の作成/更新ができない。

<VirtualHost *:80>
	ServerName	basic.mydomain.foobar
	DocumentRoot	/var/www/html.basic
</VirtualHost>

# BASIC認証
<Directory /var/www/html.basic>
	<RequireAll>
		AuthName	members
		AuthType	Basic
		AuthUserFile	/var/www/htpwd/basic
		Require		valid-user
	</RequireAll>
</Directory>

HTTP-01で使用するディレクトリ(/.well-known/acme-challenge)にはBASIC認証がかからないようにすればいいと思われるが、未検証。
特定ユーザ向けサイトなどで、サイト立ち上げの初回の証明書作成時は掛けていないが、運用開始に合わせてBasic認証を掛けた場合に更新ができずにハマりそうである。

参考URL等

下記サイトを参考にさせて頂きました。ありがとうございました。
Let'sEncrypt公式
certbot公式
Let's Encrypt (certbot) でワイルドカード証明書できた!
さくらのクラウド
certbot-dns-sakuracloudのドキュメント(公式じゃないかも?)

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?