Apache 2.4系でHTTP/2サーバを構築してみるテスト。
Let's Encryptを使ってqmailのTLSv1.2対応せっかく、Webサーバが、Forward Secrecy(FS)になったので、Let's Enctyptもパブリックベータが始まったし、メールサーバもFSに対応させたい! 2016年1月現在、Let's Enctyptの証明書を、メールサーバの証明書として利用する解説もあまりなさそうです。 ということで、番外編をやります。(HTTP/2というより、Let's Enctyptのページになってきた気もする…) 概要前提は、netqmail-1.0.6と、daemontoolと、ucspi-tcp(tcpserver)がインストールされている状態です。解説しているページは結構あると思うので、適当に検索してみてください。 今回いじるのは、tcpserverだけなので、tcpserverを使っていれば、応用可能です。 SMTPのうち、サブミッションとPOP3をTLSv1.2対応にします。 動作を確認したのは、Windows10のOutlook2016と、Android4.1のK-9 Mailです。 メールサーバ間のSMTPについては、従来通り非暗号の25番ポートなので、メッセージ本体を守るための設定ではありません。メッセージの内容を保護する場合は、PGPなどをご利用ください。 ここでの作業は、POP3と、クライアントPCからのメール送信(SMTP-Submission)の暗号化になります。SMTP/POP3認証情報や、POP3プロトコル内で受信するメールの内容などを保護します。
APOPには、脆弱性が発見されており、APOPが廃止の流れですので、APOPの代わりといった位置づけの部分だけでも意味があります。 もちろん証明書は、Let's Enctyptから取得します。 そのため、このページは、Let's Encrypt(無償の証明書発行機関)から取得を理解している前提になります。 まだの方は、こちらを先にご覧ください。 前の例と同様、WebサーバのWebrootプラグインでとってくるため、メールサーバのFQDNは、mail.example.comとし、Webサーバと同じIPとします。 メールサーバにApacheなどのWebサーバソフトウエアがインストールされていないのであれば、standaloneプラグインで取得することもできます。 メールサーバとして機能するための、DNSサーバの設定は済んでいるものとします。
準備Let'sEncrypt以前は、Webサーバと同じFQDNにして、有償の証明書を利用していた方もいると思いますが、Let's Enctyptの証明書は、いくつドメイン名があっても、無償。なので、あえて別ドメイン名で行きます。 まず、mail.example.comのサーバ証明書をとってきます。 前の例のように、バーチャルホストを作ってもいいのですが、今回は、IP直打ちなどで使われるデフォルトサーバのhtdocsを使います。 ここでは、/var/http/default/htdocs/だとします。つまり、
/usr/local/apache2/conf/httpd.conf
…(省略)… DocumentRoot "/var/http/default/htdocs" …(省略)… といった設定を想定します。この場合、以下のコマンドで、証明書が取れます。 # cd /usr/local/letsencrypt # ./letsencrypt-auto certonly -t -d mail.examile.com -a webroot --webroot-path=/var/http/default/htdocs/ --rsa-key-size 2048 --server https://acme-v01.api.letsencrypt.org/directory 一方、メールサーバにApacheなどのWebサーバソフトウエアがインストールされていないのであれば、standaloneプラグインで取得することもできます。 この場合、-a webroot --webroot-path=…を-a standaloneに置き換えます。 ファイアウォールなどを通している場合、80番ポートをあけておいてください。 # cd /usr/local/letsencrypt # ./letsencrypt-auto certonly -t -d mail.examile.com -a standalone --rsa-key-size 2048 --server https://acme-v01.api.letsencrypt.org/directory webrootプラグインか、standaloneプラグインの、いずれかの方法で、うまく証明書が取れたら、これと秘密鍵を結合するスクリプトを作ります。 # vi make_qmail_pem.sh
/etc/letsencrypt/make_qmail_pem.sh
#! /bin/sh /bin/cat /etc/letsencrypt/live/mail.examile.com/privkey.pem > /etc/letsencrypt/live/mail.examile.com/qmail.pem /bin/cat /etc/letsencrypt/live/mail.examile.com/fullchain.pem >> /etc/letsencrypt/live/mail.examile.com/qmail.pem 何でこんなことをするかというと、ucspi-tcpのtcpserver用のSSLパッチが、秘密鍵と証明書関連を1ファイルにまとめる仕様になっているからです。 実行できるようにパーミッションを設定します。 # chmod 700 make_qmail_pem.sh # ./make_qmail_pem.sh /etc/letsencrypt/live/mail.examile.com/qmail.pemが生成されているか確認してください。 # more /etc/letsencrypt/live/mail.examile.com/qmail.pem -----BEGIN PRIVATE KEY----- (秘密鍵) -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- (証明書) -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- Let's Encryptの中間証明書 -----END CERTIFICATE----- 続いて、DHE用のパラメータを生成しておきます。これは結構時間がかかります。ビビらないでください。 # openssl dhparam -out /var/qmail/control/dh_param.pem 2048 (…省略…) # chmod 600 /var/qmail/control/dh_param.pem いよいよ、ucspi-tcpのtcpserverをビルドします。
tcpserverのコンパイル# cd ~ # wget http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz # wget http://www.nrg4u.com/qmail/ucspi-tcp-ssl-20050405.patch.gz # tar xzf ucspi-tcp-0.88.tar.gz # gzip -d ucspi-tcp-ssl-20050405.patch.gz # cd ucspi-tcp-0.88 # patch < ../ucspi-tcp-ssl-20050405.patch このままでは、鍵交換にDHEおよび、ECDHEが使えないので、以下のコードを修正 即興で作ったものなので、各自自己責任でお使いください。 # vi tcpserver.c
~/ucspi-tcp-0.88/tcpserver.c
//2行目あたりに以下を追加(ECDHE用) #include <openssl/ec.h> #include <openssl/bn.h> …(省略)… //530行目あたり /* #ifdef WITH_SSL if (flagssl == 1) { /* setup SSL context (load key and cert into ctx) */ SSL_library_init(); ctx=SSL_CTX_new(SSLv23_server_method()); if (!ctx) strerr_die2x(111,FATAL,"unable to create SSL context"); /* set prefered ciphers */ if (env_get("SSL_CIPHER")) if (SSL_CTX_set_cipher_list(ctx, env_get("SSL_CIPHER")) == 0) strerr_die2x(111,FATAL,"unable to set cipher list"); if(SSL_CTX_use_RSAPrivateKey_file(ctx, certfile.s, SSL_FILETYPE_PEM) != 1) strerr_die2x(111,FATAL,"unable to load RSA private key"); if(SSL_CTX_use_certificate_chain_file(ctx, certfile.s) != 1) strerr_die2x(111,FATAL,"unable to load certificate"); } #endif */ //これを下記のものに置き換え。 #ifdef WITH_SSL if (flagssl == 1) { /* setup SSL context (load key and cert into ctx) */ SSL_library_init(); ctx=SSL_CTX_new(SSLv23_server_method()); if (!ctx) strerr_die2x(111,FATAL,"unable to create SSL context"); /* set prefered ciphers */ if (env_get("SSL_CIPHER")) if (SSL_CTX_set_cipher_list(ctx, env_get("SSL_CIPHER")) == 0) strerr_die2x(111,FATAL,"unable to set cipher list"); long nOptions= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; nOptions|=SSL_OP_NO_COMPRESSION; nOptions|= SSL_OP_CIPHER_SERVER_PREFERENCE; FILE *paramfile = fopen("/var/qmail/control/dh_param.pem", "r"); if (paramfile) { DH* dh = PEM_read_DHparams(paramfile, NULL, NULL, NULL); fclose(paramfile); if (dh != NULL) { if (SSL_CTX_set_tmp_dh(ctx, dh) != 1) { strerr_die2x(111,FATAL,"unable to set DHparams"); }else{ nOptions|=SSL_OP_SINGLE_DH_USE; } DH_free(dh); }else{ strerr_die2x(111,FATAL,"unable to read DHparams"); } } EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1); if (ecdh){ if (1 != SSL_CTX_set_tmp_ecdh (ctx, ecdh)){ strerr_die2x(111,FATAL,"unable to set EC_KEY"); }else{ nOptions|= SSL_OP_SAFARI_ECDHE_ECDSA_BUG; nOptions|=SSL_OP_SINGLE_ECDH_USE; } EC_KEY_free (ecdh); }else{ strerr_die2x(111,FATAL,"unable to new EC_KEY"); } SSL_CTX_set_options(ctx,nOptions); if(SSL_CTX_use_RSAPrivateKey_file(ctx, certfile.s, SSL_FILETYPE_PEM) != 1) strerr_die2x(111,FATAL,"unable to load RSA private key"); if(SSL_CTX_use_certificate_chain_file(ctx, certfile.s) != 1) strerr_die2x(111,FATAL,"unable to load certificate"); } #endif …(省略)… つまるところ、DHCとECDHEの初期化を追加します。ついでに,SSLv2とv3を切ります。 仕上げに、makeとインストールします。 # make # make setup これで、SSL対応の/usr/local/bin/tcpserverが、インストールされたと思います。
起動スクリプト最後に、daemontoolの起動スクリプトを書き換えます。 先ほどビルドしたtcpserverにはオプションが増えています。 -sオプションで、SSLを有効にします。さらに-nオプションで、先ほど結合した、証明書ファイルを指定します。 暗号スイートは、環境変数で設定します。SSL_CIPHER="TLSv1.2"といった感じです。 たとえば決め打ちでFSな暗号スイートを指定するため、SSL_CIPHER="DHE-RSA-AES256-GCM-SHA384"とすることもできます。 (これは、Outlook2016も対応している暗号アルゴリズムです。) 早速、daemontoolの起動スクリプトを書き換えます。 /service/qmail-pop3に平文のPOP3の設定があるとします。 # vi /service/qmail-pop3/run
/service/qmail-pop3/run
#!/bin/sh exec env - PATH="/var/qmail/bin:$PATH" SSL_CIPHER="TLSv1.2" \ /usr/local/bin/tcpserver -v -s -n /etc/letsencrypt/live/mail.example.com/qmail.pem -R -H 0 995 \ /var/qmail/bin/qmail-popup mail.example.com /usr/local/bin/checkpassword \ /var/qmail/bin/qmail-pop3d Maildir 2>&1 以下のコマンドで、tcpserverを再起動します。 # /usr/local/bin/svc -d /service/qmail-pop3 # /usr/local/bin/svc -u /service/qmail-pop3 SMTP-Submission側も同様です。 # vi /service/qmail-submission/run
/service/qmail-submission/run
#!/bin/sh exec env - PATH="/var/qmail/bin:$PATH" SSL_CIPHER="TLSv1.2" \ /usr/local/bin/tcpserver -v -s -n /etc/letsencrypt/live/mail.example.com/qmail.pem -H -R 0 465 \ /var/qmail/bin/qmail-smtpd /usr/local/bin/checkpassword 2>&1 以下のコマンドで、tcpserverを再起動します。 # /usr/local/bin/svc -d /service/qmail-submission # /usr/local/bin/svc -u /service/qmail-submission
Outlook2016の設定次に、OutlookのSSL設定を行います。 電子メールアカウント→電子メールアカウントの変更→詳細設定に進み、以下の通り、設定します。 POP3のポートを995に、「このサーバは暗号化された接続」にチェックを入れます。 SMTP側も同様、465ポートを選びます。 注意点としては、「使用する暗号化接続の種類」で「SSL」を選ぶことです。「TLS」だと、tcpserver(が使っているOpenSSL)がAcceptする段階で止まってしまいます。ここが「SSL」でも、DHE-RSA-AES256-GCM-SHA384といった、FS対応の暗号スイート(アルゴリズム)が利用できます。ネゴシエーション上、tcpserverからは、TLSv1.2に見えているので、問題ないでしょう。
AndroidのK-9 Mailの設定アカウント設定から、以下の手順で、「メール受信」、「メール送信」の設定を変更します。 POP3のポートを995に、「SSL/TLSを使用する」を選択します。 SMTPのポートは465に、「SSL/TLSを使用する」を選択します。
cronの設定Webサーバの時と同様、コマンド+オプションをシェルスクリプトに記載し、cronで、月に1回実行しましょう。qmailのpop3とsubmissionのリスタートも行います。 # vi /var/qmail//bin/cert_refresh.sh
/var/qmail//bin/cert_refresh.sh (webrootプラグインを使う場合)
#!/bin/sh /usr/local/letsencrypt/letsencrypt-auto certonly -t -d mail.example.com -a webroot --webroot-path=/var/http/default/htdocs/ --renew-by-default --server https://acme-v01.api.letsencrypt.org/directory /etc/letsencrypt/make_qmail_pem.sh /usr/local/bin/svc -d /service/qmail-pop3 /usr/local/bin/svc -u /service/qmail-pop3 /usr/local/bin/svc -d /service/qmail-submission /usr/local/bin/svc -u /service/qmail-submission
/var/qmail//bin/cert_refresh.sh (standaloneプラグインを使う場合)
#!/bin/sh /usr/local/letsencrypt/letsencrypt-auto certonly -t -d mail.example.com -a standalone --renew-by-default --server https://acme-v01.api.letsencrypt.org/directory /etc/letsencrypt/make_qmail_pem.sh /usr/local/bin/svc -d /service/qmail-pop3 /usr/local/bin/svc -u /service/qmail-pop3 /usr/local/bin/svc -d /service/qmail-submission /usr/local/bin/svc -u /service/qmail-submission 仕上げに、実行できるようにパーミッションを変えます。 # chmod 700 /var/qmail//bin/cert_refresh.sh なお、cronの設定は、短期間に連続した発行の制限がありますので、よく考えてタイミングを決めてください。 cronの起動日時は、Webサーバの証明書再取得のスクリプトとは、ずらしておいた方がいいでしょう。 たとえば、毎月10日の午前3時30分に証明書の再取得と、tcpserverのリスタートをするとすれば、 # crontab -e
/var/spool/cron/crontabs/root/
30 3 10 * * * /var/qmail//bin/cert_refresh.sh となります。これで、Let's Encryptのサービスが終わったり、障害が起きない限り、有効な証明書が、永久に維持され続けます。
|