Linux/Let's Encryptでサーバ証明書

Let's Encryptでサーバ証明書の導入(2018-03-14)


個人でも無料で導入できるサーバ証明書です。
これで最近は肩身が狭くなってきた、非httpsサイトからの脱却ができます。

詳細は Let's Encrypt(https://letsencrypt.jp/)で日本語で解説されており、
「Let's Encrypt の使い方」から、具体例に沿ってインストールできます。
ここでは参考適度に大まかな流れと、私が引っかかったところをメモしておきます。


おおまかな流れ

まずはインストールします。
私の環境はLinux(CentOS)でWebに繋がるサーバなので、yum で入りました。

# yum info certbot
# yum install certbot

そして自分が持つWebサーバの認証です。
Webサーバ(ApacheやらNginxやら)は止めずに入れることができます。

# certbot certonly --webroot -w /usr/local/apache/htdocs -d null-i.net -d www.null-i.net 

サブドメイン(上記の例では 「www.」の部分)も漏れなく設定しなければなりませんが
近いうちに(2018/2月現在は延期中の)ワイルドカード証明書が登場するかもしれません。
( *.null-i.net のように、サブドメインを * で、1つの証明書にまとめることができる、らしい)
そうなると、上記の認証コマンドが変わることになると思います。

そして、このコマンドで失敗した場合、
まずは一旦落ち着いて下さい(詳細は後述)。

初回取得の場合は規約への同意や、有効期限の連絡先メールアドレスやらの設定も対話式で行います。

デフォルトでは /etc/letsencrypt/ に、証明書が設定されました。
これを手順の例に沿って、Webサーバに設定すれば https 対応の完了です。
とても簡単ですね。
(嘘です。苦戦したので、後述)

ちなみに、私の現時点での構成はWebサーバではなく、リバースプロキシ(squid)でhttps化しているので
squid.conf に上記で取得した証明書を設定します。

https_port 443 accel cert=/etc/letsencrypt/live/null-i.net/fullchain.pem key=/etc/letsencrypt/live/null-i.net/privkey.pem (以下略)

あとは、有効期限は3か月くらいで、
期限切れの20日前に通知メールを送ってくれました。
その際には「certbot renew 」コマンドなどで更新すればOKです。

で、その更新作業を cronに入れて自動化するといいよ、
更新頻度は、証明書の発行数上限に気をつけてね、と多くのサイトで説明されていると思います。
(今ある証明書と新証明書の合計数で、発行上限を超えてしまわないように)
私の場合は、更新時に一部Webサーバの設定を変えたりしているので、しばらくは手動更新で様子を見ています。

certbot のエラーについて

例によって、証明書の取得時に何度か失敗して
連続失敗でロックがかかったしまいましたが・・・

(一時間だったっけ?とにかく英語で、
連続失敗したのでしばらく時間をおいてから再実行しなさい
という内容のメッセージが出てきたと思います。
なので、時間に余裕をもって設定作業を行うことをお勧めします)

以下の例は renew(取得済み証明書の有効期限の更新が目的)ですが、
新規取得の「certbot certonly --webroot」でも似た内容になると思います。

# certbot renew
Saving debug log to /var/log/letsencrypt/letsencrypt.log

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/null-i.net.conf
-------------------------------------------------------------------------------
Cert is due for renewal, auto-renewing...
Plugins selected: Authenticator webroot, Installer None
(中略)
Waiting for verification...
Cleaning up challenges
Attempting to renew cert (null-i.net) from /etc/letsencrypt/renewal/null-i.net.conf
 produced an unexpected error: Failed authorization procedure. www.null-i.net (http-01):
 urn:acme:error:unauthorized :: The client lacks sufficient authorization ::
 Invalid response from http://null-i.net/.well-known/acme-challenge/jMXCPEXXXX
 [160.16.214.13]: 403, null-i.net (http-01): urn:acme:error:unauthorized ::
 The client lacks sufficient authorization
(以下省略)

上記の例はサブドメインやらファイル名やら一部マスクしてます(ほんとはもっと長い)
あと、見づらいので改行も入れました。
ポイントは Invalid response from ~ 403 ~ unauthorized で、
HTTPの応答でエラー(403 Forbidden:アクセス禁止)が返って認証に失敗したって言っています。

(前略)
Waiting for verification...
Cleaning up challenges
Attempting to renew cert (null-i.net) from /etc/letsencrypt/renewal/null-i.net.conf 
produced an unexpected error: Failed authorization procedure. null-i.net (http-01): 
urn:acme:error:unauthorized :: The client lacks sufficient authorization :: 
Invalid response from http://null-i.net/.well-known/acme-challenge/ctwZZZZZZZ: 
"<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
(以下省略)

で、次は
認証に必要なファイルが見つからない(404 Not Found)、です。
こんな感じで連続失敗しているうちに、
ロックがかかって、一定時間インストール or アップデートができなくなると思います。

ここに挙げている方法(certbot certonly --webroot)の場合は、
上記ログにも出てきていますが
「Webサーバのコンテンツ置場/.well-known/acme-challenge/認証のチャレンジファイル」
というファイルを一時的に作成して、そこに外からアクセスすることで
あなたがWebサーバの持ち主であることを確認しようとしています。
(webrootオプションではなく、standaloneとかでやれば、また違う方法になるかも)

そして私の場合は、ファイアウォール(fail2ban)やリバースプロキシ(squid)で
一時的に「/.well-known」へのアクセスを許可してあげないと 403エラーや接続失敗エラーになります。
DoS対策などでURLフィルタしている環境は要注意です。

また、404エラー理由の方は
WebサーバでサブドメインやらCGIやら毎にファイルのアクセス先をいじっていた影響でした。
Apacheで言えば、VirtualHost ごとにサブドメインの DocumentRootを変えている
ScriptAlias で接続先を変えている、などなど。

あとは、設定変えた後にWebサーバ他の再読み込みを忘れたとか、
慌てるとろくな事がありません。
一旦落ち着いて、設定を見直しましょう。

あと、蛇足ですが、
過去にアクセスログに「/.well-known」への攻撃跡が残っていた理由が、このとき初めて分かりました。
あれは Let's Encrypt を想定した攻撃だったのかもしれませんね・・・
一時的に許可したファイアウォール等の設定は、作業後に忘れずに元に戻しておきましょう。

(そういうわけで、
私の環境では .well-knownへのアクセスは普段は禁止しているので
cron で自動更新する方法は、後日検討することにしました)

使う証明書を間違えないように

fullchain.pem と cert.pem のどちらを使うかは確認しましょう。

Webブラウザやopensslコマンド*1等で証明書の詳細を確認すると見れるのですが、
私の場合は「null-i.net」を証明する「let's Encrypt」を証明する「DST Root CA」ルート証明という
3段構えの証明書になっています。
fullchainを使えば「null-i.net」とその中間証明書「let's Encrypt」の両方が設定されます。
とはいえ、常に fullchain を使えば良いわけでもなく、
Webサーバやバージョンによってどこに何を設定するべきかは違うようなので、事前に確認しましょう。

私の場合は、本来は fullchainにするべきところを最初に cert.pem で設定してしまいました。
厄介だったのが、すぐに証明書エラーになればよかったんですが、
最初は見れてたのに、一か月後くらいに急に見れなくなった点です。
(ある日とつぜん「安全なサイトではありません」とか「表示できません」になりました)
さらに言えば、見れるブラウザ(IE、Chrome他)と見れないブラウザ(スマホのChrome、PCのFireFox)があって混乱しました。
どうやら中間証明書がWebブラウザのキャッシュ?に残っているか否かで、
たまたま見れたり見れなかったりするそうですが・・・

Webサーバ側の手順では「中間」証明書なんて解説は出てこないかもしれないので、
設定する際は気をつけて、可能であれば複数のWebブラウザで動作確認してみましょう。


*1 例として「openssl s_client -connect localhost:443 -showcerts」、繋いだ後にHTTP構文を手動で実行する訳ですが、今回は繋ぐまでが目的なので「Q」で即終了。

  最終更新のRSS