読者です 読者をやめる 読者になる 読者になる

koni blog

東京のウェブエンジニア koni です!ウェブサービスをガシガシ作っていきます!

Let's encryptで無料のSSL/TLS証明書を取得して独自ドメイン運用のGAEに入れて使う

Google App Engine 技術メモ

無料でSSL/TLS証明書が発行できるLets' Encryptプロジェクトが、2016年4月、ついにベータ版から正式版になりました。

jp.techcrunch.com

無料といっても、MozillaやGoogle, Facebookなどのウェブ企業や、シスコやアカマイなどのネットワーク関係の大御所も支援しているプロジェクトなので、審査がなく全自動で発行されるタイプの1,000-2,000円くらいの有料のSSL証明書と全く遜色ありません*1

業界的にウェブの暗号化に向けてこのようなプロジェクトを動かしているのは素晴らしいですね。

GAEへのSSL/TLS証明書の導入

さて、独自ドメイン運用をしているGoogle App Engine(GAE)のサイトをSSL/TLS対応をしてみましょう。

Let's Encrypt では、証明書発行の際に、ドメインの所有の確認のため、指定されたURLにファイルをアップロードする必要があります。よくあるプロセスですね。

通常のサーバーの場合は、この確認用のファイルの設定や、Apache/nginxなどの設定もcertbotというプログラムが証明書の取得とあわせてやってくれるのですが、GAEの場合証明書の設定はGUIでしかできません。

そこで、証明書の取得のみ行うmanualモードで行います。なのでこのためにわざわざサーバーを立てる必要はありません。以下では Mac OSX 10.11.4で作業しました。

1. 独自ドメインの設定を終えておく

まずは、独自ドメインがGAEで表示できる状態にしておきます。 あとのステップで、Let's Encrypt から取得しようとする証明書用のサーバーにリクエストが来て所有の確認が行われるので、DNSの設定などは済ませておく必要があります。

2. 証明書の取得

まずは、Let's Encrypt のクライアントのインストールを行います。

cloneします。10MBほどあるので、そこそこ時間かかります。

$ git clone https://github.com/certbot/certbot
$ cd certbot

それでは早速証明書を取得してみましょう。初回は必要なプログラムのインストールが行われるので、時間がかかります。 また環境のrootのPWを求められる場合があります。

初回のみ、メールアドレスを聞かれるのと、利用規約への同意を求められます。 ちなみにこのcert-onlyのonlyというのは、インストールも行うrunに対して、インストールはしない、という意味です。 また以前は、letsencrypt-autoでしたが、2016年5月からcertbot-auto に変更になったそうです。

$ ./certbot-auto certonly --manual
# PWを求められるかも

必要なミドルウェアのインストールが終わると、次のような画面になります。 ここに取得予定のドメインを入力します。カンマ区切りスペース区切りで複数可。

f:id:konisimple:20160602230440p:plain

次にクライアントのIPアドレスがログに記録され公開されることに対する同意確認画面。Yesで進みます。

f:id:konisimple:20160602230413p:plain

次に以下のようなメッセージが表示されます。

Make sure your web server displays the following content at
http://cheetahapp.net/.well-known/acme-challenge/gTIjcnRpydLV5lcRDD-b-2TcTRh4YyZC26jDSZOx2ck before continuing:

gTIjcnRpydLV5lcRDD-b-2TcTRh4YyZC26jDSZOx2ck.5Hvrmt1oBopQ03IDSAdTZRRoXZACheMnLi_Y272bLx4

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

mkdir -p /tmp/certbot/public_html/.well-known/acme-challenge
cd /tmp/certbot/public_html
printf "%s" gTIjcnRpydLV5lcRDD-b-2TcTRh4YyZC26jDSZOx2ck.5Hvrmt1oBopQ03IDSAdTZRRoXZACheMnLi_Y272bLx4 > .well-known/acme-challenge/gTIjcnRpydLV5lcRDD-b-2TcTRh4YyZC26jDSZOx2ck
# run only once per server:
$(command -v python2 || command -v python2.7 || command -v python2.6) -c \
"import BaseHTTPServer, SimpleHTTPServer; \
s = BaseHTTPServer.HTTPServer(('', 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \
s.serve_forever()"
Press ENTER to continue

ここははやる気持ちを抑えてまだENTERは押しません!!

指示どおりに、Let's Encryptからのメッセージの存在確認用URLにテキストを置きます。 上記の場合は、以下のURLで以下が表示されるようにします。

URL: http://cheetahapp.net/.well-known/acme-challenge/gTIjcnRpydLV5lcRDD-b-2TcTRh4YyZC26jDSZOx2ck

内容: gTIjcnRpydLV5lcRDD-b-2TcTRh4YyZC26jDSZOx2ck.5Hvrmt1oBopQ03IDSAdTZRRoXZACheMnLi_Y272bLx4

GAEでは以下の様に設定します。

lets_encrypt.txt:

gTIjcnRpydLV5lcRDD-b-2TcTRh4YyZC26jDSZOx2ck.5Hvrmt1oBopQ03IDSAdTZRRoXZACheMnLi_Y272bLx4

app.yaml:

- url: /.well-known/acme-challenge/gTIjcnRpydLV5lcRDD-b-2TcTRh4YyZC26jDSZOx2ck
  static_files: lets_encrypt.txt
  upload: lets_encrypt.txt

デプロイします。

$ appcfg update .

さっきのURLをクリックして内容が表示されることを確認したら、エンターを押します。

しばらくすると、以下のような内容が表示されて無事証明書が取得できました。

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/cheetahapp.net/fullchain.pem. Your cert will
   expire on 2016-08-31. To obtain a new or tweaked version of this
   certificate in the future, simply run certbot-auto again. To
   non-interactively renew *all* of your ceriticates, run
   "certbot-auto renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

証明書と秘密鍵は/etc/letsencrypt/live/[domain_name]にあります。

$ sudo ls /etc/letsencrypt/live/cheetahapp.net
cert.pem    chain.pem   fullchain.pem   privkey.pem

秘密鍵を復号化します。

$ sudo openssl rsa -in /etc/letsencrypt/live/[domain_name]/privkey.pem -out /etc/letsencrypt/live/[domain_name]/privkey_no_pass.pem

3. GAEへの登録

GCPのコンソールから、GAE→設定→SSL 証明書→新しい証明書をアップロードの順に開きます。 「PEM でエンコードされた X.509 公開鍵証明書」の欄に、fullchain.pemを、 「復号化された PEM でエンコードされた RSA 秘密鍵」の欄にprivkey_no_pass.pemをペーストします。

ここで復号化を忘れると選択した秘密鍵は有効ではないようです。というエラーメッセージが表示されます。これ結構はまりましたw

4. 動作確認

無事に設定できると、以下のようにアドレスバーが緑になります。やった!!

f:id:konisimple:20160602231741p:plain

課題 証明書が3ヶ月で切れてしまう

SSL証明書は3ヶ月で切れてしまいます。通常年単位での更新なのでこれはちょっと面倒です。 サーバー自体にcertbotを入れれば、/etc/letsencrypt/live/[domain_name]に常に最新に証明書のシンボリックリンクが貼られるので手間はないのですが、GAEだとそうはいきません。 証明書の再取得はコマンドできるのですが、GAEへの証明書の送信はAPIなどあるのでしょうか。軽く探したところは見つかりませんでした。

3ヶ月おきにフォーム行くのは地味に面倒なので、そこに1000円払うと割りきって既存のSSL業者を使う、というのもありかもしれません。

証明書の更新 (2016/11/1 追記)

早速3か月経ったので、証明書の更新を行いました。 更新でもファイルをアップロードする必要がありますが、アップロードするURLとファイル内容は同じなので、コマンド押していけば簡単に新しい証明書を取得できます。 コマンドさえメモっておけば5分もあれば更新完了するので、そんなに手間でもありませんね。

ただまあGAEとかに関してはこの作業完全自動化してくれたら嬉しいんですけどねー。。

まとめ

GAEのSSL対応、これがあれば5分くらいで終わってしまいますね。 いつもSSL対応は、秘密鍵作ってそれでCSR作って会社のサイトのフォームに行って発行依頼して、メールクリックして、証明書DLしてなど複雑な手順だったので、かなり簡単になりました。 しかも全部無料、提供しているのがシスコ・アカマイ、Google、Facebookなので割と安心、ということで、銀行などが使っているアドレスバーに緑の組織名が表示されるEV SSL以外はどんどん移行が進むんじゃないでしょうか。

参考

qiita.com 秘密鍵の復号化で同じはまりをされていた方w

qiita.com 同様のことをGCEのインスタンスで行った事例。

*1:どちらも改ざんと盗聴には効果がありますが、なりすましには無力です。