Let's Encrypt (以下LE)のcertbotで、証明書を取得しようとしたときに
Failed authorization procedure. hogehoge.scriptlife.jp (tls-sni-01): urn:acme:error:unauthorized :: The client lacks sufficient authorization :: Incorrect validation certificate for TLS-SNI-01 challenge. Requested (リクエスト文字列) from xxx.xxx.xxx.xxx:443. Received 2 certificate(s), first certificate had names "fuga.scriptlife.jp"
というエラーが出てきてしまったときの対応。
動作を察することができれば、ある意味なんてことはない感じでしたが…わからぬ…
(hogehoge.scriptlife.jp、fuga.scriptlife.jpはVirtualHostに設定しているURL、xxx.xxx.xxx.xxxはIPアドレスに読み替えて下さい。)
目次
サーバが返している証明書に記載されたホストが、認証してもらおうとしているドメインと違っていた
結論からいいますと、hogehoge.scriptlife.jpにHTTPSでアクセスしたときに返っていた証明書がfuga.scriptlife.jpのものになっていたために、失敗していたのでした。
どうしてこうなってしまったのかという状況は、ちと複雑なので後回しにしますが、これに気づいた時点で対応としては2通り考えました。
ひとつは、返しているオレオレ証明書をhogehoge.scriptlife.jpで作る。
もうひとつは、HTTPで認証を通す。
ここでは後者の方法で解決します。(といいますか前者は試していないので、上手くいくかわかりません…)
HTTPでLEの認証をする
失敗していたときは、certbotのオプションとして「--apache」を使用していました。
# certbot certonly -t -d hogehoge.scriptlife.jp --apache
という感じで。
この「--apache」は、現在動作しているapacheサーバーを通して認証キーにアクセスするものです。
で、これがHTTPSで取ってこようとする。
だからHTTPで取ってこようとするオプションを探して色々見ていたところ、「--webroot」を使えばよいということを見つけました。
# certbot certonly -t -d hogehoge.scriptlife.jp --webroot -w /var/www/html
という感じです。(/var/www/htmlはDocumentRootを指定してください。ここに認証キーが出力されます)
私の場合は、これで上手くいきました。
そもそもHTTPSの設定をしているときにHTTPSの認証を求められるのどうかしているとか思っていたのですが、HTTPで取得する設定は別にあったようで助かりました。
「--apache」は新規ではなく更新用の設定かもしれません。
どうしてこうなった的な話
ここからは少し背景的な話。このエラーもまた、原因が複数あるような感じがするので、何かの参考になればと思います。
まず状況として、ひとつのサーバーの上でhogehoge.scriptlife.jpとfuga.scriptlife.jpという2つのサイトを運用しようとしていました。
そのためHTTPSのVirtualHostで、それぞれを区分けしていました。IPアドレスは共通でxxx.xxx.xxx.xxxです。
で、先にfuga.scriptlife.jpのほうの証明書をLEから取得していて、これは上手くいっていました。
ただこのときに、certbotはデフォルトで動作していたようで、この証明書をデフォルトのSSL証明書として設定してしまっていました。
(このときはどうやって取得したのか? という疑問はあると思います。たぶんwebrootを試したりしていたのでしょう)
そのために、ssl.confにある「<VirtualHost _defalt:443>」に、fuga.scriptlife.jpの証明書がセットされ、デフォルトではこちらが返されるようになりました。
こういう状態ですので、fuga.scriptlife.jpを対象にしたcertbotは当然うまく動作します。
ですがhogehoge.scriptlife.jpは動かない。ということになりました。
個別のssl設定ファイルは何度もいじっていたのですが、まさかssl.confのほうが書き換わっていたとは…
(いや、ssl.confを変更するみたいなメッセージも見た気はします…)
ここで先に作業していたfuga.scriptlife.jpの登録が成功していたことも、気づきを遅くしたポイントでして。
IPアドレスは同じドメインで、返ってきたメッセージに「from xxx.xxx.xxx.xxx」とか「first certificate had names …」とか書いてあったので、同じIPでは何か特別な設定をしないとLEで証明書を取得できないのではないかという疑惑もあって。
ApacheのVirtualHostで複数の証明書が使えるようになったことは知っていたためあきらめなかったのですが、この考えからLEのほうの設定を探していました。
結局はssl.confの設定に気づいて、これをローカルのオレオレ証明書にしてみたら、返ってきたメッセージが「first certificate had names "fuga"」(「fuga」はこのサーバーのホスト名)となったので、察したところです。
standaloneは起動できなかった
このLEのツール、certbotはいくつかモードがあって、今回使っていたapacheとwebrootはHTTPサーバーに乗っかる形での認証でしたが、certbotが自前でHTTP/HTTPSサーバーを起動して認証するstandaloneモードというものも用意されていました。
今回の私のような状況だと、これで解決できるかと思ったのですが動かなかった。
エラーはよく覚えていません…
なぜ--apacheを使っていたのか
そもそもなぜ、webrootのほうを使わなかったのか。最初のほう仕組みをよく分かっていなかった、というところはあります。
めっさ単純な話、ドキュメントに
このプラグインは、SSL/TLS サーバ証明書の取得と、Apache ウェブサーバへの証明書のインストール(Apache の設定)の両方を自動化します。
って書いてあったから「おっええやん!」って感じで使ってみたのが裏目った。
ちなみにその下にはwebrootの説明があり、
Certbot クライアントを実行するコンピュータでウェブサーバ(httpd)が動作中であり、ウェブサーバを停止することなく SSL/TLS 証明書を発行したい場合には、Webroot プラグインをご利用ください。
となっています。
なんとなく、HTTPでアクセスできるようなニュアンスを感じられるかもしれない説明ですね!
表のところには、apacheはAuthとInstにY、webrootはAuthがYでInstにNが付いており、また説明にも
Webroot プラグインは、コマンドラインオプションで certonly と --webroot を指定することで使用可能です。
とあったので、証明書を最初にインストールするには不向きだと思っていたところもあります。
実際には、certonlyが証明書の取得、installがssl.confの書き換えという動作であるため、私が求めていたのはcertonlyのほうだったということでしたが。
さらに、別プラグインではあるけどstandaloneのほうは、HTTPとHTTPSの選択がオプションで提供されており、apacheも同じ作りだろうと探していたことが追い撃ち。
まとめ
ポイントとして押さえるべきは以下の点。
- LEはHTTP/HTTPSでアクセスできるディレクトリに認証ファイルを置いて、LEのシステムのサーバからそこにアクセスし認証する
- apacheプラグインはHTTPSでアクセス
- webrootプラグインはHTTPでアクセス
LEで作成した後の証明書は通常の証明書と同じ扱いでよく、この後に行うことはApacheのVirtualHostなどの設定になります。
ダウンロードされた証明書は/etc/letsencrypt/live以下に参照できるシンボリックリンクがありますから、そちらを読み込むようにSSLの設定を変更していきます。
つかれた。