Let's EncryptでSSL証明書の新規作成と自動更新(http-01編)

Let's Encrypt とは

  • Lets' Encrypt は認証局(Certificate Authority)のブランドの一つである。

  • これは「Symantec(旧Verisign)セキュア・サーバーID」「CyberTrust SureServer」「SecomTrust セコムパスポート for Web3.0」「GlobalSign クイック認証SSL」「GeoTrust RapidSSL」「Comodo PositiveSSL」などの一つと考えれば良い。

  • たぶんどれかは聞いたことあるはずと思う。アレが抜けてるというツッコミは却下で:-)。
  • 他の認証局と同じような点は、
    • 1証明書をどのように(複数IP、複数バックエンド、複数プロトコル)使用しても1取得で済む(安い認証局は大抵そうだよね)。
    • 親ドメインをまたぐ、マルチドメイン証明書(Subject Alternative Names)に対応している(全ての認証局で対応してるね)。
    • いよいよワイルドカード証明書に対応(対応してるブランドと対応してないブランドとあるね)。

    • DV(Domain Validation)証明書のみ提供(DVだけでなくOV・EVにも対応してるブランドもあるね)。

    • ただしOV(Organization Validation)証明書やEV(Extended Validation)証明書との純技術的な優劣は無い。

  • 他の認証局と明確に違う点は、
    • 無償。
    • RSA(2048bit3072bit4096bit), ECDSA(prime256v1secp384r1) の5種類の鍵が選べる(ここまで選べるブランドは限られるね)。DSAが無い?時代だ。諦めろ。

    • ACME(Automated Certificate Management Environment)プロトコルによる証明書の認証から発行までの一連のバッチ化(自動化)が可能。

    • 今どき誤差だけど、扱える端末が(他の認証局と比べて)少ない。
    • ごく一部のエンドユーザーが粘り強く使用しているような、全アクセスの0.1%未満の端末であってもサポートしないといけない用途であるならお勧めしない。
    • 逆に今どきのメジャーどころの端末・ブラウザは対応している。
    • よってPC相手にはほぼ問題無い(Windows XP? IE6? 知らんがな)。

    • 取得数制限(特に単位時間あたりの)があるので注意。詳しくは Rate Limits を参照のこと。

    • 検証(ステージング)用認証局も用意されているので、セットアップ時の検証や、ACMEクライアントの開発といった用途ではこちらを使う。

    • 「現在の」ルート証明書は「IdentTrust|DST(Digital Signature Trust) Root CA X3」である。

    • IdentTrust なの? DST なの? については旧会社のブランドも残ってるらしい、としか自分は認識してない。詳しくは会社概要でも読んでくれい。

    • 少なくとも中間証明書の発行者(Issuer)はそうである(Let's Encrypt運用元の ISRG - Internet Security Research Group ではない)。

    • このルート証明書がインストールされた端末が対応端末となる。
    • 中間証明書(Subject)は「Let's Encrypt Authority X3」である(場合によってはこっち「も」入ってることがあるかもしれない)。

  • なおツールとしては certbot が代表的だが、他にもたくさんのツールが存在する。

  • ここでは全て dehydrated を使用を前提に解説する。certbotdehydratedの違いについては特に解説しない。

  • dehydratedを選んだ理由は、

    • dehydratedはBash/ZSH依存スクリプトであるため、特別な言語環境(Python)を必要としない。

    • certbotの場合、Pythonに依存する分には問題無いが、依存するPythonモジュールが極めて大量にあって維持が大変。

    • dehydratedはまだ依存が少ない(curl のせいでずいぶん増えてるが)。

    • dehydratedの場合、わけわかんなくなっても、シェルスクリプトなのでソースコード読んで理解できる。また長いコードではない。

    • dehydratedはWebサーバー機能を内蔵していないため、Webサーバーとの競合に配慮しなくてよい。

    • dehydratedはエイリアス機能により、同じコモンネームでRSA/ECDSA両方の証明書取得が可能である。

http-01 とは

目次

検証環境

検証作業内容

dehydrated のセットアップ

初期セットアップ

いくつかのディレクトリの作成および設置ルールを決める。

証明書の設置場所

# 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

ドメイン所有者確認トークンディレクトリの指定

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/etc/dehydrated/config)

設定ファイル例(/usr/local/etc/dehydrated/config)

   1 alias openssl="/usr/bin/openssl"
   2 
   3 RENEW_DAYS="30"
   4 KEY_ALGO="prime256v1"
   5 #KEY_ALGO="rsa" KEYSIZE="2048"
   6 CONTACT_EMAIL="メールアドレス"
   7 #テスト発行したい場合、以下の2行を有効にすること。
   8 #CA="https://acme-staging.api.letsencrypt.org/directory"
   9 #CA_TERMS="https://acme-staging.api.letsencrypt.org/terms"
  10 

コモンネームファイル(/usr/local/etc/dehydrated/domains.txt)

example.org www.example.org
example.com www.example.com wiki.example.com

初回実行ないしは手動更新の仕方

dehydrated --register --accept-terms
dehydrated -c

自動更新設定

weekly_dehydrated_enable="YES"
weekly_dehydrated_deployscript="/usr/local/etc/dehydrated/deploy.sh"

/usr/local/etc/dehydrated/deploy.sh 例

#/bin/sh
/usr/sbin/service apache24 restart && /usr/local/bin/dehydrated -gc

Apache の設定例

SSL証明書の参照方法

  SSLCertificateFile    /usr/local/etc/dehydrated/certs/コモンネーム/fullchain.pem
  SSLCertificateKeyFile /usr/local/etc/dehydrated/certs/コモンネーム/privkey.pem

  SSLCertificateFile      /usr/local/etc/dehydrated/certs/コモンネーム/cert.pem
  SSLCertificateChainFile /usr/local/etc/dehydrated/certs/コモンネーム/chain.pem
  SSLCertificateKeyFile   /usr/local/etc/dehydrated/certs/コモンネーム/privkey.pem

チャレンジ・レスポンスファイルの参照設定

Alias /.well-known/acme-challenge/ /usr/local/www/dehydrated/

<Directory /usr/local/www/dehydrated>
  Options       None
  AllowOverride None
  Require       all granted
  Header        add Content-Type text/plain
</Directory>

よくある質問とその答え

Q. ECDSA対応は必須?

A. やってみたけど、必須というほど対応しているブラウザは多く(種類的に)はないですね。 ごく最新の有名どころブラウザはともかく、四方山ブラウザを考慮するとまだまだ。 サーバー側でRSAとECDSAの両方を提案してブラウザが受け入れられる方を…という解決策も無くもないですが(使えるか知らないし興味ない)、 結局RSAの鍵も作らないと行けないことには変わりないので、当面、RSA2048オンリーで行くのが正解かと。

Q. ports/security/dehydrated と ports/security/py-certbot とどっちがいいですか?

A. 目標が違うのでどっちとも言えない。 certbot は Let' Encrypt 推奨ACMEクライアントなのでそちらを頑張るのもありかと。 自分はシェルスクリプトで記述されてる、依存が certbot より少ないという理由で採用しただけとなります。

ACMEクライアントは、certbot、dehydrated だけでなく、他にもあるので、チェックしてみるといいかもしれない。

あと、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)。続きはWebで

参考文献

【付録】 dehydrated v0.40 での変更

v0.40 で、ライセンス受諾の確認が必須になりました。 それまでは暗黙の受諾として、dehydrated が勝手に受諾していましたが、 別途手動で、dehydrated --register --accept-terms を実行する必要があります。

ステージング用のライセンス受諾ともまた別の話となりますので、 CA だけでなく、CA_TERMS も合わせて設定する必要があります。

この振る舞いは /usr/local/etc/dehydrated/accounts/ハッシュキー/account_key.pem の有り無しがトリガーとなりますので、 既にこのファイルがある環境では影響有りません。

初回実行に手動で実行していれば気がつくレベルとなります(エラーメッセージ等「読まない」人についてはノーコメント)。

【付録】 letsencrypt.sh から dehydrated への移行

商標上の理由で、letsencrypt.sh から dehydrated へ名前変更が実施された。 合わせてディレクトリから設定まで色々変更になったので対応についてメモっておく。

ディレクトリ名の変更

/usr/local/etc/letsencrypt.sh から /usr/local/etc/dehydrated へ変更になったわけであるが、更新後は新しいディレクトリが作成されていることもあり、こまめに手を入れる必要がある。

/usr/local/etc/letsencrypt.sh/config.sh

mv /usr/local/etc/letsencrypt.sh/config.sh /usr/local/etc/dehydrated/config

※config.sh から config に変更になったので合わせて変更を実施する。

/usr/local/etc/letsencrypt.sh/deploy.sh

mv /usr/local/etc/letsencrypt.sh/deploy.sh /usr/local/etc/dehydrated/

/usr/local/etc/letsencrypt.sh/domains.txt

mv /usr/local/etc/letsencrypt.sh/domains.txt /usr/local/etc/dehydrated/

/usr/local/etc/letsencrypt.sh/hook.sh

mv /usr/local/etc/letsencrypt.sh/hook.sh /usr/local/etc/dehydrated/

/usr/local/etc/letsencrypt.sh/certs/

mv /usr/local/etc/letsencrypt.sh/certs /usr/local/etc/dehydrated/
  • certs ディレクトリはインストール時には作成されない。
  • SSL証明書取得時にコモンネームと合わせて作成される。
  • 既に /usr/local/etc/dehydrated/certs ディレクトリが作成されている場合は、子ディレクトリ(コモンネーム)を個別にリネーム(移動)すること。

/usr/local/etc/letsencrypt.sh/archive/

mv /usr/local/etc/letsencrypt.sh/archive /usr/local/etc/dehydrated/
  • archive ディレクトリはインストール時には作成されない。
  • SSL証明書クリーンナップ(-gc オプション指定)時にコモンネームと合わせて作成される。
  • 既に /usr/local/etc/dehydrated/archive ディレクトリが作成されている場合は、子ディレクトリ(コモンネーム)を個別にリネーム(移動)すること。

後始末

rmdir /usr/local/etc/letsencrypt.sh

※全ての移動が完了すれば、ディレクトリもファイルも残ってないはずなので削除する。

設定ファイルの変更

リネームによる影響で変更になるファイルは以下の3ファイルである。 ディレクトリ名およびコマンド名に letsencrypt.sh というキーワードが無いか確認し、dehydrated に置き換えること。

  • /usr/local/etc/dehydrated/config
  • /usr/local/etc/dehydrated/deploy.sh
  • /usr/local/etc/dehydrated/hook.sh

SSL証明書利用アプリケーションの設定変更

本例では Apache(2.4)を例に説明した。 当該箇所のディレクトリ名変更を新しいディレクトリ名に変更する。

SSL証明書の旧指定例

  SSLCertificateFile    /usr/local/etc/letsencrypt.sh/certs/コモンネーム/fullchain.pem
  SSLCertificateKeyFile /usr/local/etc/letsencrypt.sh/certs/コモンネーム/privkey.pem

トークンディレクトリの旧指定例

Alias /.well-known/acme-challenge/ /usr/local/etc/letsencrypt.sh/.acme-challenges/

<Directory /usr/local/etc/letsencrypt.sh/.acme-challenges>
  Options       None
  AllowOverride None
  Require       all granted
  Header        add Content-Type text/plain
</Directory>

起動設定(periodic)の変更

/etc/periodic.conf あるいは /etc/periodic.conf.local のどちらかの設定で定期更新を実施しているわけだが、変数名が変更になっている。

本例では以下のような設定を実施しているが、

weekly_letsencrypt_enable="YES"
weekly_letsencrypt_deployscript="/usr/local/etc/letsencrypt.sh/deploy.sh"

下記のように変更する。

weekly_dehydrated_enable="YES"
weekly_dehydrated_deployscript="/usr/local/etc/dehydrated/deploy.sh"

単純に letsencrypt や letsencrypt.sh を dehydrated に置き換えるだけである。

certificate/レッツエンクリプトでSSL証明書の新規取得と自動更新(http-01編) (最終更新日時 2019-05-08 17:20:04 更新者 NorikatsuShigemura)