CentOSにLet's EncryptのSSL証明書を導入する
やってみたので、手順をまとめました。実施したのはCentOS6+Apache2.2という、やや古い環境ですがCentOS7とかでも基本的には同じはずです。
Let's Encryptの概要
Let's Encryptは無料のSSL証明書を発行する認証局。 特徴は料金無料であるのと、専用のクライアントコマンドを使って証明書の発行を行う点。またワイルドカードの証明書は発行できない。有効期限が3ヶ月で、更新もコマンドによって自動化するのが前提となっています。
証明書を発行する際の要件として、当然ドメイン所有者の認証(本当にそのドメインの所有者か確認を行うこと)が必要になります。通常の認証局はメールなどを使ってこれを行いますが、Let's EncryptはACMEプロトコルという通信プロトコルと専用のクライアントコマンドを使います。ACMEプロトコルについて以下の記事が参考になりました。
Let's Encrypt を支える ACME プロトコル - Block Rockin’ Codes
ざっくり理解したところでは、ACMEプロトコルの内容は難しいものではなく、HTTPをベースに使った証明書の自動発行手順といった感じのものです。
さて、実際にLet's Encryptの証明書を導入するには一般に以下の作業が必要です。
- クライアントコマンドのインストール
- HTTPサーバの用意
- クライアントコマンドを実行して証明書を取得
- 取得した証明書使うためのHTTPサーバの設定
- 自動更新のための設定
以下、順に記述します。
手順
クライアントコマンドのインストール
ACMEプロトコルでLet's Encryptのサーバと通信して証明書発行を行うCLIツールです。ここでは公式が提供しているcertbot-auto
というツールを使います。
シェルスクリプトとPythonで構成されています。このツールの操作自体、基本的にroot特権が必要になるので、以下のインストール作業のコマンドも全てrootユーザで行いました。
# yum install -y epel-release # curl https://dl.eff.org/certbot-auto -o /usr/bin/certbot-auto # chmod a+x /usr/bin/certbot-auto # certbot-auto --os-packages-only --non-interactive
最後のcertbot-auto --os-packages-only --non-interactive
で依存パッケージがインストールされます(pythonのランタイムとか)。
HTTPサーバの用意
証明書発行時にACMEプロトコルはドメインの認証処理(acme challengeというらしい)において、証明書を発行するドメインに対してHTTPでリクエストを投げてきます。 よってHTTPサーバが稼働している必要があります。ここではapache使うことにします。
# yum install -y httpd
インストールしたらドメイン名でアクセスできるように設定しておきます。
クライアントコマンドを実行して証明書を取得
certbot-auto certonly
で証明書を取得します。証明書発行に必要な秘密鍵などもこのコマンドを叩くだけでまとめて生成されます。
# certbot-auto certonly --non-interactive --agree-tos --webroot -w /var/www/html -d example.com --email kohki.makimoto@gmail.com
以下のオプションは環境に合わせて読み替えてください。
-d
: ドメイン名を指定します。--email
: 更新期限が近づいたときにメール通知されるメアドを指定します。-w
: HTTPサーバのドキュメントルートを指定します。
-w
オプションについて補足します。前述したようにACMEプロトコルはドメインの認証処理でHTTPサーバにアクセスしてくるのですが、その際/.well-known/acme-challenge/
というパスに対してアクセスしてきます。クライアントコマンドはこのパスにLet's Encrypt が指定したテキストを配置する必要があるので、そこにアクセスできるようドキュメントルートを指定するわけです。
その他オプションについての詳細はcertbot-auto --help all
で確認してください。
うまくいくと
/etc/letsencrypt/live/{ドメイン名}
というパスに証明書や秘密鍵が生成されます。
取得した証明書使うためのHTTPサーバの設定
最近はSNIを使ってバーチャルホストごとにSSL設定ができるので、SSL証明書の設定はバーチャルホストごとに設定しました。
<VirtualHost *:443> ServerName example.com # ... SSLEngine on SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem </VirtualHost>
なお、サーバ全体のSSL設定は/etc/httpd/conf.d/ssl.conf
などに以下のように記述しておきます。
LoadModule ssl_module modules/mod_ssl.so AddType application/x-x509-ca-cert .crt AddType application/x-pkcs7-crl .crl SSLPassPhraseDialog builtin SSLSessionCache shmcb:/var/cache/mod_ssl/scache(512000) SSLSessionCacheTimeout 300 SSLMutex default SSLRandomSeed startup file:/dev/urandom 256 SSLRandomSeed connect builtin SSLCryptoDevice builtin SSLStrictSNIVHostCheck off Listen 443
また、必要に応じてhttpにアクセスがあったらhttpsにリダイレクトさせる設定もいれます。
<VirtualHost *:80> ServerName example.com RewriteEngine On RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R,L] </VirtualHost>
自動更新のための設定
certbot-auto renew
コマンドで証明書の更新ができます。Let's Encryptの証明書は3ヶ月で有効期限が切れるので、cronに以下のコマンドを仕込みます。この例は出力を捨ててますが、ちゃんと運用する場合はきちんとログに残しましょう。
50 3 * * * root certbot-auto renew --post-hook "/usr/sbin/apachectl graceful" > /dev/null 2>&1
証明書取得時のようにドキュメントルートの指定はしていないので、/etc/letsencrypt/
配下の設定ファイルなどを見て更新しているっぽいです。
–-force-renew
をつけて実行すると有効期限が1ヶ月未満にならなくても、強制的に有効期限を更新します。手動で更新検証するのに使いました。
以上で一通り、作業は完了です。
その他
Basic認証をかけたサイトにLet's Encryptを使う
Basic認証をかけているサイトだとACMEプロトコルのドメイン認証で、HTTPサーバにアクセスできず、証明書取得ができません。
以下の設定を入れて/.well-known/acme-challenge
に穴をあけておくとうまくいきます。
<Location /> Satisfy Any AuthType Basic AuthName "My Private Stuff" AuthUserFile /var/www/example/.htpasswd Require valid-user SetEnvIf Request_URI "/.well-known/acme-challenge" acme-challenge Order Deny,Allow Deny from all Allow from env=acme-challenge </Location>
サードパーティツール
クライアントツールはサードパーティーのGo実装のシングルバイナリもあるのですが、現状見送り。公式のほうがやはり安心感ある。
CentOS6のpythonのバージョンが古い
CentOS6はpythonのバージョンが古いのでcertbot-auto実行時に以下のような警告がでました。が、正常に証明書取得までできたのでまあいいかな、と。。。
/root/.local/share/letsencrypt/lib/python2.6/site-packages/cryptography/__init__.py:26: DeprecationWarning: Python 2.6 is no longer supported by the Python core team, please upgrade your Python. A future version of cryptography will drop support for Python 2.6 DeprecationWarning
いろいろ参考にさせていただいたサイトなど
- Let’s EncryptのSSL証明書で、安全なウェブサイトを公開 - さくらのナレッジ
- Let's Encrypt を支える ACME プロトコル - Block Rockin’ Codes
- Go言語でLet's EncryptのACMEを理解する | SOTA
- Support HTTP Basic Authentication with webroot · Issue #1744 · certbot/certbot · GitHub
ありがとうございました。