## page was renamed from SSL証明書/Let's EncryptでSSL証明書の新規取得と自動更新(http-01編) = Let's EncryptでSSL証明書の新規作成と自動更新(http-01編) = == Let's Encrypt とは == <> == http-01 とは == * サイト利用者を証明するための「チャレンジ・レスポンス」のやりとりをHTTP(http-01)で行う方法である。 * 一応HTTPSで行う tls-sni-01 もあるが、まぁ使うことは無いでしょう。 * 「SSL証明書利用」イコール「Webサーバーで使う」というユースケースにおいては、手軽で罠も少なく、わかりやすい手順かと。 * 複数のWebサーバー、他のプロトコル(SMTP、IMAP4等)での利用が想定されるのであれば、[[SSL証明書/Let's EncryptでSSL証明書の新規取得と自動更新(dns-01編)|もう一方]]の手順をお勧めする。 * もちろん共存できない話では無いので、こちらで慣れたところで、もう一方に手を出すのは全く問題無し。 * そのあたりは証明書単位で選択可能なので、共存不可能でも無いです。 == 目次 == <> == 検証環境 == * 以下のソフトウェアの利用を前提に検証を実施した。いずれも最新のリリースということで確認しているが、ある程度古い環境でも問題無いと思われる。 * OS: FreeBSD 11.0-R * ACMEクライアント: dehydrated 0.4.0 * Webサーバー: Apache 2.4.27 * 上記以外の環境では、以下の点に相違が発生する。必要に応じて読み替えたし。 * インストール方法 * インストールされるディレクトリ * 自動更新のための手続きとその設定 * 逆に以下の点は参考にできる。 * 設定パラメータとその意味 * 運用事例 == 検証作業内容 == * 本例では、www.example.jp というサイトに対して証明書を発行するものとする。 * また証明書取得後のWebサーバー(Apache 2.4 での例)への反映(Deploy)までを手順化する。 = dehydrated のセットアップ = * [[https://www.freshports.org/security/dehydrated|ports/security/dehydrated]] をインストールする。 * この時 [[https://www.freshports.org/security/dehydrated|ports/security/py-certbot|certbot]] のインストールは不要である。 * certbot はあって動かなくなることは無いが、あっても使用されることも無い。 * また、定期実行が設定ファイルに1行記述するだけで制御できるレベルで簡単である。 * ただ、この事情は ports メンテナの功績によるものなので:-)、他の(OS)環境でそうであるかは不明である。 == 初期セットアップ == いくつかのディレクトリの作成および設置ルールを決める。 === 証明書の設置場所 === * ports/security/dehydrated では /usr/local/etc/dehydrated/certs/コモンネーム/ 以下に、以下のファイルが設置される。 * /usr/local/etc/dehydrated/certs/コモンネーム/cert-UNIXタイムスタンプ.csr * /usr/local/etc/dehydrated/certs/コモンネーム/cert-UNIXタイムスタンプ.pem * /usr/local/etc/dehydrated/certs/コモンネーム/chain-UNIXタイムスタンプ.pem * /usr/local/etc/dehydrated/certs/コモンネーム/fullchain-UNIXタイムスタンプ.pem * /usr/local/etc/dehydrated/certs/コモンネーム/privkey-UNIXタイムスタンプ.pem * 設置場所についてはプログラム中に直接記載されているため、変更は不可能である。 * その代わり、シンボリックリンクで誘導することは可能。 * また、最新(現在)の証明書に対してシンボリックリンクが張られる。 {{{ # cd /usr/local/etc/dehydrated/certs/コモンネーム # ls -alF total 122 -rw------- 1 root wheel 436 May 29 06:02 cert-1464469337.csr -rw------- 1 root wheel 1533 May 29 06:02 cert-1464469337.pem lrwx------ 1 root wheel 19 May 29 06:02 cert.csr@ -> cert-1464469337.csr lrwx------ 1 root wheel 19 May 29 06:02 cert.pem@ -> cert-1464469337.pem -rw------- 1 root wheel 1647 May 29 06:02 chain-1464469337.pem lrwx------ 1 root wheel 20 May 29 06:02 chain.pem@ -> chain-1464469337.pem -rw------- 1 root wheel 3180 May 29 06:02 fullchain-1464469337.pem lrwx------ 1 root wheel 24 May 29 06:02 fullchain.pem@ -> fullchain-1464469337.pem -rw------- 1 root wheel 302 May 29 06:02 privkey-1464469337.pem lrwx------ 1 root wheel 22 May 29 06:02 privkey.pem@ -> privkey-1464469337.pem }}} * cert.pem(署名済みSSL証明書公開鍵)+chain.pem(中間証明書)=fullchain.pem(両者を足したモノ) の使い分けは利用するサーバープログラムの仕様に従うこと。 * なお、Let's Encrypt の中間証明書(chain.pem)を世間一般のブラウザが持っていることは「現在」期待しない方がよい。限定的には持っているブラウザもあるが、広く世間で使おうと思ったら、持っていない前提で運用すべき。 === ドメイン所有者確認トークンディレクトリの指定 === * ドメイン所有者確認トークンの設置場所(ディレクトリ)を決める。 * 「ドメイン所有者確認トークン」はドメインの所有者であること確認するための「トークン」(一時発行キー)である。 * これはWebサーバー側の設定とも連動する話なので、その前提で決定する。 * 以下はアクセスログ(例)である。 {{{ 66.133.109.36 - - [29/May/2016:06:02:21 +0900] "GET /.well-known/acme-challenge/チャレンジトークン HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)" }}} * デフォルトで /usr/local/www/dehydrated となっている。 * またこの設定は「WELLKNOWN」変数で変更可能である。 === アカウントキーの保存ディレクトリの指定 === * アカウントキーと呼ばれるJSONとRSA秘密鍵の保存ディレクトリを指定する。 * デフォルトで /usr/local/etc/dehydrated/private_key.{json,pem} となる。 * これら設定は「ACCOUNT_KEY_JSON」(.json)と「ACCOUNT_KEY」(.pem)設定で指定が可能である。 == 設定ファイル(/usr/local/etc/dehydrated/config) == * 上記準備と合わせて、設定ファイルに記載する。いわゆるシェルスクリプトなので、その記法はそれに準じる。 * 設定ファイルは /usr/local/etc/dehydrated/config である(シェル文法で記述)。 * ports の場合、config.example が同じディレクトリにインストールされるので、合わせて参照して欲しい。 * 色々と設定する項目はあるが、下記の設定のみ意識すればよい。実際にはもっと使わない。 * WELLKNOWN * ACCOUNT_KEY * ACCOUNT_KEY_JSON * RENEW_DAYS * PRIVATE_KEY_RENEW * KEY_ALGO / KEYSIZE * CONTACT_EMAIL * WELLKNOWN, ACCOUNT_KEY, ACCOUNT_KEY_JSONについてはすでに解説済みなので、残りについて説明する。 * RENEW_DAYS * 有効期限「残」日数を指定する。今日を基準に有効期限が指定日数(秒換算)未満になったら更新を行う。 * 勘違いしやすいのでもう一度。「今日+RENEW_DAYS」が有効期限を越えると更新を行う。 * 「60」だと「有効期限の60日前に更新」、「30」だと「有効期限の30日前に更新」となる。 * なおFreeBSDでは、更新そのものは毎週行われる(periodic の weekly 指定、つまり7日単位に丸められる)。 * PRIVATE_KEY_RENEW * 更新する毎に秘密鍵を作り直すか否かを指定する。 * デフォルトで「yes」である(毎回作り直す)。 * 指定可能な値は「yes」か「それ以外」かしか無いので、「Yes」と書いてもNoと解釈される。 * また「作り直さない」選択にメリットも無ければ推奨でもないので、ごく極めて例外的な何かが無ければ「yes」を選択すること。 * KEY_ALGO / KEYSIZE * SSL証明書の鍵アルゴリズム(KEY_ALGO)と鍵サイズ(KEYSIZE)を指定する。 * KEY_ALGO での選択可能な識別子は「rsa」「prime256v1」「secp384r1」。 * KEY_ALGO が「rsa」の時に限って KEYSIZE を指定する(2048、3072、4096)。 * CONTACT_EMAIL * Let's Encrypt では連絡用メールアドレスの指定が必要となるので、メールアドレスを指定する。 === 設定ファイル例(/usr/local/etc/dehydrated/config) === {{{#!highlight sh alias openssl="/usr/bin/openssl" RENEW_DAYS="30" KEY_ALGO="prime256v1" #KEY_ALGO="rsa" KEYSIZE="2048" CONTACT_EMAIL="メールアドレス" #テスト発行したい場合、以下の2行を有効にすること。 #CA="https://acme-staging.api.letsencrypt.org/directory" #CA_TERMS="https://acme-staging.api.letsencrypt.org/terms" }}} == コモンネームファイル(/usr/local/etc/dehydrated/domains.txt) == * 発行するSSL証明書のコモンネームを列挙したファイルを作成する。 * このファイル名は /usr/local/etc/dehydrated/domains.txt で指定される。 * 1行1証明書で、1カラム目はコモンネームとなり、2カラム目以降はSANs(Subject Alternative Names)を指定する。 * 以下のサンプルでは example.org, example.com の2枚の証明書を作成/更新する。 {{{ example.org www.example.org example.com www.example.com wiki.example.com }}} * また、「example.org」のSANとして「www.example.org」が、「example.com」のSANとして「www.example.com」と「wiki.example.com」が合わせて設定される。 * 他にも、以下のルールで処理される。 * 大文字は小文字に変換される。 * 複数の空白類(スペース、タブなど)で区切り、1個の空白として処理される。 * 行頭が # や空行は無視。 == 初回実行ないしは手動更新の仕方 == * 以上の設定が完了したら、コマンドを root で実行する。 * {{{-c}}} オプションは {{{--cron}}} と同じ意味である(だからどうした!:-)。 {{{ dehydrated --register --accept-terms dehydrated -c }}} * とりあえずプログラムを読んだ限りでは環境変数汚染依存はなさそう。 * 正直、LANG、LC_* くらいはケアして欲しいところだけど。 == 自動更新設定 == * ports/security/dehydrated では定期実行に [[https://man.freebsd.org/periodic(8)|periodic(8)]] を採用している。 * よって定期実行は /etc/periodic.conf ないしは /etc/periodic.conf.local ファイルにて設定を行う。 {{{ weekly_dehydrated_enable="YES" weekly_dehydrated_deployscript="/usr/local/etc/dehydrated/deploy.sh" }}} * 単純に更新するだけなら、{{{weekly_dehydrated_enable="YES"}}} と設定するだけで良い。 * 全ての更新が完了した後、サーバーへの反映を行うスクリプトを weekly_dehydrated_deployscript 変数で指定できる。 * weekly_dehydrated_deployscript 変数で指定されたファイルは、実行権限(chmod +x)も必要。 * ただし、証明書の更新が無くても実行されるので、厳密には証明書が更新されたか確認した方がいい。 * とは言え、現地時間で毎週土曜日04時05分(/etc/crontab の periodic weekly 行参照のこと)に実行されるので、そのあたりはテキトーでもいいかもしれない。 * なお {{{dehydrated -gc}}} は古い証明書の削除(クリーンナップ)を行う。 * わざと残しておくのであれば実行は不要である。 === /usr/local/etc/dehydrated/deploy.sh 例 === {{{ #/bin/sh /usr/sbin/service apache24 restart && /usr/local/bin/dehydrated -gc }}} = Apache の設定例 = == SSL証明書の参照方法 == * 例えば Apache(2.4.8以上)では以下のように指定することになる。 {{{ SSLCertificateFile /usr/local/etc/dehydrated/certs/コモンネーム/fullchain.pem SSLCertificateKeyFile /usr/local/etc/dehydrated/certs/コモンネーム/privkey.pem }}} * 古い Apache(2.4.8 未満・2.4.8 以降でもOK)だと以下のパターンで指定する。 {{{ SSLCertificateFile /usr/local/etc/dehydrated/certs/コモンネーム/cert.pem SSLCertificateChainFile /usr/local/etc/dehydrated/certs/コモンネーム/chain.pem SSLCertificateKeyFile /usr/local/etc/dehydrated/certs/コモンネーム/privkey.pem }}} == チャレンジ・レスポンスファイルの参照設定 == * Apache(2.4.x)の場合、以下のように設定する。 {{{ Alias /.well-known/acme-challenge/ /usr/local/www/dehydrated/ Options None AllowOverride None Require all granted Header add Content-Type text/plain }}} = よくある質問とその答え = == Q. ECDSA対応は必須? == A. やってみたけど、必須というほど対応しているブラウザは多く(種類的に)はないですね。 ごく最新の有名どころブラウザはともかく、四方山ブラウザを考慮するとまだまだ。 サーバー側でRSAとECDSAの両方を提案してブラウザが受け入れられる方を…という解決策も無くもないですが(使えるか知らないし興味ない)、 結局RSAの鍵も作らないと行けないことには変わりないので、当面、RSA2048オンリーで行くのが正解かと。 == Q. ports/security/dehydrated と ports/security/py-certbot とどっちがいいですか? == A. 目標が違うのでどっちとも言えない。 certbot は Let' Encrypt 推奨ACMEクライアントなのでそちらを頑張るのもありかと。 自分はシェルスクリプトで記述されてる、依存が certbot より少ないという理由で採用しただけとなります。 ACMEクライアントは、certbot、dehydrated だけでなく、[[https://letsencrypt.org/docs/client-options/|他にもある]]ので、チェックしてみるといいかもしれない。 あと、certbot はWebサーバー内蔵で http(TCP ポート 80)開いてるかぎり使える点がうれしいかも。 ただ、既にWebサーバーが稼働済みの場合、certbot よりも、Webサーバーを内蔵してない dehydrated の方が都合がよいと思われる。 == Q. 下記のように所有者確認アクセスに失敗、証明書が更新されません! == {{{ 66.133.109.36 - - [29/May/2016:04:45:29 +0900] "GET /.well-known/acme-challenge/チャレンジトークン HTTP/1.1" 404 268 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)" }}} A. Webサーバーの設定ミスの可能性があります! 自分は「{{{Alias /.well-known/acme-challenge/ /usr/local/www/dehydrated}}}」と最後に「/」を入れ忘れていました! このケースでは Alias の第一、第二引数ともに最後に「/」を含める必要がある。 他にも良くありそうなのが、設定した後にサーバー再起動(ないしは再読み込み)を忘れていたなどが考えられる。 あとリカバリとして、更新に失敗して残ってるCSRや秘密鍵を削除するのに {{{dehydrated -gc}}} を実施すること。 == Q. Webサービス立ち上げてないサーバーでSSL証明書使いたいです! == A. そんなあなたにDNS認証(dns-01)。[[../Let's EncryptでSSL証明書の新規取得と自動更新(dns-01編)|続きはWebで]]。 = 参考文献 = * [[https://wiki.freebsd.org/BernardSpil/LetsEncrypt|BernardSpil/LetsEncrypt]] * [[https://github.com/lukas2511/dehydrated|dehydrated]] * [[https://certbot.eff.org/|Certbot]] * [[https://letsencrypt.jp/|Let's Encrypt 総合ポータル]] * [[https://letsencrypt.jp/docs/using.html|Let's Encrypt ユーザーガイド]] * [[https://letsencrypt.org/docs/rate-limits/|Rate Limits]](SSL証明書取得数制限) * [[https://letsencrypt.org/docs/staging-environment/|Staging Environment]](ステージング環境) * [[https://letsencrypt.org/docs/client-options/|ACME Client Implementations]](ACMEクライアント実装) <>