行政書士ボット

機械学習で進化する行政書士Gyobot Blog

2017年12月20日23:05(約2318日前)

Djangoで開発したWebアプリケーションをLet's EncryptでSSL対応する(Apache編)

開発

WebアプリをSSL対応した方が良い理由

以前からのGoogleのHTTPSサイト優遇方針に加えて、2017年10月からhttp通信の場合Chromeでアドレスバーに「保護されていない通信」と表示されるようになってしまいました。
GyobotはWeb上のボットのためフォーム入力が必要。「保護されていない通信」のアラート自体が、ユーザーに不安感を与える要因になってしまいます。ユーザーの安心感のためにSSL対応は必須です。
もちろん実際にSSL対応によって通信が暗号化されるセキュリティ上の価値の恩恵を受ける必要もありました。

Djangoでは証明書の読み込みのために置き場所の指定が必要

Djangoは静的ファイルをそのまま配信することができません。そのためWebアプリケーション内に証明書ファイルの置き場所を指定する記述が必要です。
この点が自分がSSL対応したときにはまったポイントでしたが、それ以外は大きなトラブルなく設定できたかなと思います。

HTTPS (443) ポートの開放

firewalld によってアクセスが遮断されないように以下のように443ポートを解放します。

$ firewall-cmd --add-service=https --zone=public --permanent
$ firewall-cmd --reload

全部設定しても遮断されてしまう場合は、SELinuxの設定など他のセキュリティー設定も適宜見直してみてください。

DjangoプロジェクトをApacheで動かす場合のSSL対応

具体的な作業内容は以下になります。また動作環境は既にhttpでWebサイトが稼働していることを前提とします。
想定しているドメインはhttps://hoge.comと仮定しています。

動作環境

  • CentOS7.3.6
  • Apache2.4.6
  • Python3.6.2
  • Django1.11.6

httpとhttpsの混在をなくす

ひとつのコンテンツ内にhttpとhttps通信が混在している場合、混在コンテンツ(mixed content) として安全性が確保されないためSSL対応をしても「保護されていない通信」のアラートが表示されてしまいます。そのため実際に通信が発生するページ内のhttpコンテンツを除去する必要があります。


hoge

このようにコンテンツ内のプロトコル部分の記述を削除するなどして混在コンテンツ(mixed content) を除去します。

certbotのインストール

certbotはLet’s Encryptの証明書発行と設定を自動化するためのプログラムです。certbotがLet’s Encryptサーバーとやり取りすることで証明書の発行を自動化されます。

$ yum install epel-release
$ yum install certbot python-certbot-apache

管理者権限でcertbotをインストールするためのepelリポジトリをインストールしてからpython-certbot-apache をインストールします。

Install  2 Packages (+37 Dependent packages)
Upgrade             (  9 Dependent packages)

Total download size: 12 M
Is this ok [y/d/N]: y

インストール中に上記のような質問が返された場合はyにします。「Complete!」が返されればインストール完了です。

Djangoプロジェクト内settings.pyの設定

.well-knownはDjangoに設定する証明書までの静的パスの場所になりますので適宜好きなように変更してください。
新しく指定するディレクトリの場合は実際にWebサーバー内に上記のディレクトリ(空でOK)を作成することも忘れないようにしてください。

CERT_ROOT = os.path.join(BASE_DIR, '.well-known')
CERT_URL = '/.well-known/'

次にurls.pyの設定をします。

Djangoプロジェクト内urls.pyの設定

django_hoge_project/urls.pyに以下の設定を追記します。

urlpatterns += static.static(settings.CERT_URL, document_root=settings.CERT_ROOT)

以下よりApacheの設定に移ります。

Apacheの設定ファイルssl.confにバーチャルホストの設定

cartbotのインストルが完了すると/etc/httpd/conf.d/ssl.confファイルができていますのでこの中にバーチャルホストの設定をします。

$ vim ssl.conf

以下のような設定を最終行に追加します。

Alias /.well-known/ /var/www/html/django_hoge_project/.well-known/
<Location /.well-known/>
    Options -Indexes

.well-knownはDjangoに設定した静的パスの場所(これから発行する証明書ファイルの場所)になりますので適宜変更してください。

Apacheの設定ファイルwsgi.confにバーチャルホストの設定

DjangoをApacheで動かすためのmod_wsgiの設定を変更します。
いろいろと設定がありますが、http://hoge.comもhttp://www.hoge.comもhttps://www.hoge.comもhttps://hoge.comにリダイレクトさせる場合の例です。

NameVirtualHost *:80
NameVirtualHost *:443
LoadModule wsgi_module /var/www/html/env/lib64/python3.6/site-packages/mod_wsgi/server/mod_wsgi-py36.cpython-36m-x86_64-linux-gnu.so
WSGISocketPrefix /var/run/wsgi

<VirtualHost *:443>
ServerName hoge.com

SSLEngine On
SSLCertificateFile /etc/letsencrypt/live/hoge.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/hoge.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/hoge.com/chain.pem

WSGIDaemonProcess myapp user=hoge group=hoge
WSGIProcessGroup myapp
WSGIScriptAlias / /var/www/html/django_hoge_project/hoge_project/wsgi.py

<Directory /var/www/html/django_hoge_project/hoge_project>

  Order allow,deny
  Allow from all



Alias /favicon.ico /var/www/html/django_hoge_project/hoge/static/favicon.ico
Alias /static/ /var/www/html/django_hoge_project/static/
Alias /media/ /var/www/html/django_hoge_project/media/

<Directory /var/www/html/django_hoge_project/static>
  Order deny,allow
  Allow from all


<Directory /var/www/html/django_hoge_project/media>
  Order deny,allow
  Allow from all



<VirtualHost *:80>
ServerName hoge.com

RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]


<VirtualHost *:80>
ServerName www.hoge.com

RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://hoge.com%{REQUEST_URI} [R=301,L]


<VirtualHost *:443>
ServerName www.hoge.com
 
SSLEngine On
SSLCertificateFile /etc/letsencrypt/live/hoge.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/hoge.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/hoge.com/chain.pem

RewriteEngine on
RewriteRule ^(.*)$ https://hoge.com%{REQUEST_URI} [R=301,L]


URLの変更はページの移転を意味します。[R=301,L]はHTTPステータスコード 301指定することで、検索エンジンにページの移転を教えてあげるための設定です。
この記事は既にhttp通信でDjangoプロジェクトが動いている場合にSSL対応することを想定しています。
もしLoadModuleの設定などwsgi.confの設定が不明な場合は、フレームワークは違いますがwsgi.confの設定は似ているのでBottleで作成したWebアプリケーションを本番環境に適用するの記事を参考にしてみてください。

Apacheの再起動

設定を有効にするためにApacheを再起動します。

$ systemctl restart httpd

これで証明書発行の準備が完了しました。以下で実際に証明書を発行します。

証明書を発行する

certbotコマンドで証明書を発行します。 -dオプションにドメイン、-wオプションにssl.confにも指定した証明書までの静的パスの場所を指定します。--emailは証明書の有効期限を知らせるためのメールアドレスです。

$ certbot certonly --webroot -w /var/www/html/django_hoge_project/.well-known/ -d hoge.com --email=xxx@xxx.xx

証明書発行のための応答が始まります。

-------------------------------------------------------------------------------
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v01.api.letsencrypt.org/directory
-------------------------------------------------------------------------------
(A)gree/(C)ancel: A

規約の同意です。Aを選択します。

-------------------------------------------------------------------------------
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about EFF and
our work to encrypt the web, protect its users and defend digital rights.
-------------------------------------------------------------------------------
(Y)es/(N)o: N

メーリングリストの受信可否を選択します。受け取りたければ Y、受け取りたくなければ N を選択します。

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/hoge.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/hoge.com/privkey.pem
   Your cert will expire on 2018-03-15. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot 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

証明書の作成が成功すると上記のメッセージが表示されます。
以上の作業でhttps通信での接続が可能になります。接続できない場合はセキュリティ周りの見直しやApacheの再起動など適宜試してみてください。

Let’s Encryptの証明書を自動更新する

証明書の発行が完了し無事SSL対応が完了しました。しかしLet’s Encryptの証明書は3ヶ月ごとに更新しなければ効力がなくなってしまいます。certbot renewコマンドをたたいて手動で更新しても問題ありませんが、忘れてしまうこともありえます。
そのためcornに自動更新の設定をしておくことが現実的です。cartbotを利用していれば簡単に自動更新の設定ができます。

証明書の更新にはroot権限が必要

$ crontab -u root -e

上記のコマンドで管理者権限のcronに設定していきます。

証明書の更新とApache再起動の自動化

毎月深夜1時に証明書の更新とApacheの再起動をさせるときのcrontabの設定です。

00 01 01 * * certbot renew && systemctl restart httpd

書式は分 時 日 月 曜日 コマンドとなっています。
certbot renewは更新間近にならないと更新が実行されないのでタイミング的に更新されるか心配な場合は、週1回など自動更新の頻度を短くしても問題ないようです。
renewの後に--dry-runオプションをつけることで実際には更新せずに更新のシミュレーションをことができます。

まとめ

以上で、Djangoで開発したWebアプリケーションのSSL化ができました。
search consoleを使用している場合などhttpからhttpsにURLが変わることで再登録が必要になるツールもありますので、忘れずに設定しましょう。

関連記事