話題の記事

Let’s EncryptでValidなSSL/TLS証明書を取得する

2015.10.27

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ども、大瀧です。

無償で利用できるSSL証明書発行サービスであるLet's Encryptがクローズドベータになりました。早速ベータ申請が通ったので、証明書を発行してみた様子をレポートします。

letsenc01

動作確認環境

  • 端末 : OS X El Capitan
  • Webサーバー : Debian Wheezy

手順

現在はクローズドベータなので、事前にベータにエントリーしていたメールアドレスに招待メールが届くことで利用可能になります。手順自体は以下のページでアナウンスされているものです。

まずはローカルにユーティリティをインストール&実行します。OSXの場合は自動でHomebrewを検出し依存ソフトウェアがインストールされます。環境を汚したくないという方はDockerを利用するのも良いでしょう。プレビュー版のものですが、@sawanobolyさんの以下のQiitaエントリーが詳しいです。

$ git clone https://github.com/letsencrypt/letsencrypt
  :
$ cd letsencrypt/
$ ./letsencrypt-auto --agree-dev-preview --server \
> https://acme-v01.api.letsencrypt.org/directory auth
Bootstrapping dependencies for Mac OS X...
WARNING: Mac support is very experimental at present...
==> Installing dependencies for augeas: libxml2
==> Installing augeas dependency: libxml2
==> Downloading https://homebrew.bintray.com/bottles/libxml2-2.9.2.el_capitan.bo
######################################################################## 100.0%
==> Pouring libxml2-2.9.2.el_capitan.bottle.1.tar.gz
==> Caveats
This formula is keg-only, which means it was not symlinked into /usr/local.

OS X already provides this software and installing another version in
parallel can cause all kinds of trouble.

Generally there are no consequences of this for you. If you build your
own software and it requires this formula, you'll need to add to your
build variables:
    LDFLAGS:  -L/usr/local/opt/libxml2/lib
    CPPFLAGS: -I/usr/local/opt/libxml2/include

==> Summary
?  /usr/local/Cellar/libxml2/2.9.2: 275 files, 10M
==> Installing augeas
==> Downloading http://download.augeas.net/augeas-1.4.0.tar.gz
######################################################################## 100.0%
==> ./configure --prefix=/usr/local/Cellar/augeas/1.4.0
==> make install
==> Caveats
Lenses have been installed to:
  /usr/local/share/augeas/lenses/dist
==> Summary
?  /usr/local/Cellar/augeas/1.4.0: 419 files, 3.9M, built in 111 seconds
==> Downloading https://homebrew.bintray.com/bottles/dialog-1.2-20150528.el_capitan.bottle.tar.gz
######################################################################## 100.0%
==> Pouring dialog-1.2-20150528.el_capitan.bottle.tar.gz
?  /usr/local/Cellar/dialog/1.2-20150528: 13 files, 824K
Creating virtual environment...
-n Updating letsencrypt and virtual environment dependencies...
-n .
-n .
-n .

画面がブルーバックのTUIに切り替わります。[1.Manual Authenticator]にカーソルがあることを確認し、[Enter]を押下します。

letsenc02

ベータリクエストに記載したメールアドレスを入力します。

letsenc03

使用許諾画面では[Agree]にカーソルがあることを確認し、[Enter]を押下します。

letsenc04

証明書を発行するドメインを入力します。

letsenc05

しばらく待つとTUI画面からCUIに切り替わり、以下のメッセージが表示されます。ユーザーがドメインのオーナーであるかを認証するために、ドメイン以下の特定URLへのサーバーレスポンスを自動生成し、Let's Encryptのホストからリクエストを送出、レスポンスを検証します。メッセージの前半が検証要件、If you don't have HTTP server configured, you can run the following command on the target server (as root):から後ろの後半はPythonで要件を満たす簡易Webサーバー起動するためのコマンド一覧です。メッセージの最後にPress ENTER to continueとありますが、[Enter]キーを押すと先ほどの検証が実行されるため、サーバーの準備が整うまで放置しておきましょう。

Make sure your web server displays the following content at
http://www.takipone.com/.well-known/acme-challenge/91OhqnUB4ct7sdT-4EbhopZk_RS4Qzn_PGp3nKKo4ms before continuing:

{"header": {"alg": "RS256", "jwk": {"e": "AQAB", "kty": "RSA", "n": "2zpa2Lk-bfZcjqAaUQZByoQ6n4PhW-BC6wiujAPhLyF1ZNEv704o4PjXuJP3M2RetAHluUpMikFgD302guSbX8BUZSfsGzYZ9xdaSV0S3aGO8iq-kpZLuEZn_ijWv49vx6hu21J838_uriK6kPOo1gWD6LmP5p1cJi-HJ8x08UwWOFdzJrVaydqtPJ8iiHKmkHbltElsLUyXPAib3fPcHgTuZiDyPKRUpVa-KAA-RRTRgQNQhipVAeBZlxuwkz6cI_fRASkjQz7ixx8atseVgCOzmRIr8ExXL0ksWdmwOkKvu4xMGT2hfes-8dX-mTsfTa2ZZNLPLmAMwhrolbvE7Q"}}, "payload": "eyJ0bHMiOiBmYWxzZSwgInRva2VuIjogIjkxT2hxblVCNGN0N3NkVC00RWJob3Baa19SUzRRem5fUEdwM25LS280bXMiLCAidHlwZSI6ICJzaW1wbGVIdHRwIn0", "signature": "wTg-MEog6l3zWrUlc7AXazBCKCi3nt1tJP-o1D5nZzG2OSTALXbG9I-PaalCCf8w_L167NzyD78J-WxhW1jLerVj7XHF2DFaiZNuRkGlvODPpS4oi2oU38tR7wwUpoeGy5xnlzb5VUjECACyG5-22HddAk41-qk2d1JNH8tCo78UrG-uYmS3vMDtL8LKJrT7RuX_nVrXaW4sgogtOTIBmv6RLF2Nd8RqeSFE3kkinok0XvqBVAdS1R4zME6XZUWayCu31TWIsgnu7lH_ZZBKn3hgHIm7hc1P1La9xKLeQb5nROhNfzuHcPUm1AiApu8N-4hzM8Yt-pNEkbbQiJOp4Q"}

Content-Type header MUST be set to application/jose+json.

If you don't have HTTP server configured, you can run the following
command on the target server (as root):

mkdir -p /tmp/letsencrypt/public_html/.well-known/acme-challenge
cd /tmp/letsencrypt/public_html
echo -n '{"header": {"alg": "RS256", "jwk": {"e": "AQAB", "kty": "RSA", "n": "2zpa2Lk-bfZcjqAaUQZByoQ6n4PhW-BC6wiujAPhLyF1ZNEv704o4PjXuJP3M2RetAHluUpMikFgD302guSbX8BUZSfsGzYZ9xdaSV0S3aGO8iq-kpZLuEZn_ijWv49vx6hu21J838_uriK6kPOo1gWD6LmP5p1cJi-HJ8x08UwWOFdzJrVaydqtPJ8iiHKmkHbltElsLUyXPAib3fPcHgTuZiDyPKRUpVa-KAA-RRTRgQNQhipVAeBZlxuwkz6cI_fRASkjQz7ixx8atseVgCOzmRIr8ExXL0ksWdmwOkKvu4xMGT2hfes-8dX-mTsfTa2ZZNLPLmAMwhrolbvE7Q"}}, "payload": "eyJ0bHMiOiBmYWxzZSwgInRva2VuIjogIjkxT2hxblVCNGN0N3NkVC00RWJob3Baa19SUzRRem5fUEdwM25LS280bXMiLCAidHlwZSI6ICJzaW1wbGVIdHRwIn0", "signature": "wTg-MEog6l3zWrUlc7AXazBCKCi3nt1tJP-o1D5nZzG2OSTALXbG9I-PaalCCf8w_L167NzyD78J-WxhW1jLerVj7XHF2DFaiZNuRkGlvODPpS4oi2oU38tR7wwUpoeGy5xnlzb5VUjECACyG5-22HddAk41-qk2d1JNH8tCo78UrG-uYmS3vMDtL8LKJrT7RuX_nVrXaW4sgogtOTIBmv6RLF2Nd8RqeSFE3kkinok0XvqBVAdS1R4zME6XZUWayCu31TWIsgnu7lH_ZZBKn3hgHIm7hc1P1La9xKLeQb5nROhNfzuHcPUm1AiApu8N-4hzM8Yt-pNEkbbQiJOp4Q"}' > .well-known/acme-challenge/91OhqnUB4ct7sdT-4EbhopZk_RS4Qzn_PGp3nKKo4ms
# run only once per server:
$(command -v python2 || command -v python2.7 || command -v python2.6) -c \
"import BaseHTTPServer, SimpleHTTPServer; \
SimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map = {'': 'application/jose+json'}; \
s = BaseHTTPServer.HTTPServer(('', 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \
s.serve_forever()"
Press ENTER to continue

今回はwww.takipone.comのDNSに登録したマシンでPythonスクリプトを実行します。rootユーザーになってからコピペでOKです。

ryuta@instance-1:~$ sudo -i
root@instance-1:~# mkdir -p /tmp/letsencrypt/public_html/.well-known/acme-challenge
root@instance-1:~# cd /tmp/letsencrypt/public_html
root@instance-1:/tmp/letsencrypt/public_html# echo -n '{"header": {"alg": "RS256", "jwk": {"e": "AQAB", "kty": "RSA", "n": "2zpa2Lk-bfZcjqAaUQZByoQ6n4PhW-BC6wiujAPhLyF1ZNEv704o4PjXuJP3M2RetAHluUpMikFgD302guSbX8BUZSfsGzYZ9xdaSV0S3aGO8iq-kpZLuEZn_ijWv49vx6hu21J838_uriK6kPOo1gWD6LmP5p1cJi-HJ8x08UwWOFdzJrVaydqtPJ8iiHKmkHbltElsLUyXPAib3fPcHgTuZiDyPKRUpVa-KAA-RRTRgQNQhipVAeBZlxuwkz6cI_fRASkjQz7ixx8atseVgCOzmRIr8ExXL0ksWdmwOkKvu4xMGT2hfes-8dX-mTsfTa2ZZNLPLmAMwhrolbvE7Q"}}, "payload": "eyJ0bHMiOiBmYWxzZSwgInRva2VuIjogIk9ubTB5bERiMTlkZU1wdEI0eExhdE9NM0ExcDJWRS1CWXJfSXJ0OU9yLVEiLCAidHlwZSI6ICJzaW1wbGVIdHRwIn0", "signature": "A3qTQ1IsmuqxV_zvNJIARUI4eZ-WrecRZKOEEHoM7gsCRHS8oj27QzbSglhHcx0TKYcCnUbxsCEGSG2g9SGOEqyJih7psMPgNzcZpRI1PwrO_VEZb1MZ2zYJRhsXUPAIrcaNRzAuQnNqhp1IWdGP81zqauqboyds-AdJPlCYNtmMibbKQXEagb5A4tSEGvkKT-CB0zbK_2fk9hGO0BX7hZkwG0-VTavm7GsZieCUSwPtUAuJuIGNLWv9yPDdPbn3Fk_VadAcjDjW5zkY13W0aGvA7eg9HndJfqeCQbuMVqAKb8TNJx9pU8NjmZq1OQUM3_fDHgqiQ6pacBN1SZR56w"}' > .well-known/acme-challenge/Onm0ylDb19deMptB4xLatOM3A1p2VE-BYr_Irt9Or-Q
root@instance-1:/tmp/letsencrypt/public_html# # run only once per server:
root@instance-1:/tmp/letsencrypt/public_html# $(command -v python2 || command -v python2.7 || command -v python2.6) -c \
> "import BaseHTTPServer, SimpleHTTPServer; \
> SimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map = {'': 'application/jose+json'}; \
> s = BaseHTTPServer.HTTPServer(('', 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \
> s.serve_forever()"

フォアグラウンドで80番ポートをListenし、クライアントからの接続を待ち受けます。 Let's Encryptのユーティリティを実行する端末に戻り、[Enter]を押下すると検証が実行されます。 サーバーの端末にアクセスログが表示され、ユーティリティの端末には検証が成功したことと証明書が保存されたことを示すメッセージが表示されます。

サーバーの端末

XX.XX.XX.XX - - [26/Oct/2015 15:12:51] "GET /.well-known/acme-challenge/Onm0ylDb19deMptB4xLatOM3A1p2VE-BYr_Irt9Or-Q HTTP/1.1" 200 -

Let'

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/www.takipone.com/fullchain.pem. Your cert
   will expire on 2016-01-24. To obtain a new version of the
   certificate in the future, simply run Let's Encrypt again.
$

証明書は/etc/letsencrypt/live/<ドメイン名>/に配置されます。

$ sudo ls /etc/letsencrypt/live/www.takipone.com
Password:
cert.pem	chain.pem	fullchain.pem	privkey.pem
$

できていますね!

動作検証

今回は、Nginxで試してみました。Let's EncryptのSSL証明書は中間証明書を含むため、中間証明書を指定するディレクティブの無いNginxの場合はfullchain.pem(サーバー証明書と中間証明書のセット)を使いましょう。

/etc/nginx/site-enabled/default

  :
# HTTPS server
#
server {
	listen 443;
	server_name www.takipone.com;

        root html;
	index index.html index.htm;

	ssl on;
	ssl_certificate     certs/fullchain.pem;
	ssl_certificate_key certs/privkey.pem;

	ssl_session_timeout 5m;

	ssl_protocols SSLv3 TLSv1;
	ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP;
	ssl_prefer_server_ciphers on;

	location / {
		try_files $uri $uri/ =404;
	}
}

Firefox 41.0.2でアクセスした様子が以下です。証明書エラーなしで正常に接続できています。

letsenc06

証明書ビューアは以下のような感じ。

letsenc07

Chrome 46.0でも正常に接続できました。

letsenc08

まとめ

現在はベータなので証明書の有効期限や発行回数に制限があるため実用するのはまだ早いですが、GAの準備が確実に進んでいる様子がうかがえますね。