【Azure】Ubuntu 18.04 × Bottle × Let's Encrypt で SSL対応

Bottleはお手軽に使えるWebサーバとしてとても重宝します。
で、自宅Webサーバを公開したいわけですが、極力限定的にしたく、インターネットに全公開!はやめたいので、Azure上に組んだVMにBottleを入れ、外部公開はそのVMにやらせ(一枚かませ)ます。また、そのVMは外部とのSSL終端をさせて、リバースプロキシらしきものとして動かします。

なので、必要な技術としては
・Azure VMの実装
・Bottleの導入
・通信のSSL
です。

1.Azure VMの実装

といっても、これは割愛。Microsoftのアカウントを作ってAzureにアクセス。コンソールからVMを作るだけ。
ただし、サーバとして公開する最低限の設定として、グローバルIPの固定IP化(何個かまでは無料だったはず)、ネットワーク設定での送信元IPアドレス/送信先ポート番号の限定化をします。
もっといえば、Application Gatewayを導入したほうがより安全(WAFとして使う)。

2.Bottleの導入

Bottleは1ファイルでできています。AzureVMを立ち上げてwgetで入手可能。

$ wget http://bottlepy.org/bottle.py

サンプルは公式に書いてあるので、その通りにPythonソースファイルを作ればOK。
bottlepy.org

ひとまず動くことを確認する。

$ python helloworld.py
※Webサーバが起動するので、ブラウザでアクセス。

3.Let's Encryptを導入する

letsencrypt.org
Let's Encryptを使えば無料でSSL化が可能です。用途的にはオレオレ証明書でも同じですが、作る手間とかアクセス時のブラウザの警告とか考えるととてもありがたいサービスです。

■参考サイト
loumo.jp

AzureVMにSSHログインして以下のコマンドを実行します。

$ sudo wget https://dl.eff.org/certbot-auto -O /usr/sbin/certbot-auto
$ sudo chmod a+x /usr/sbin/certbot-auto

今回はAzureVMを利用しますが、事前にドメインは設定しておかないといけません。
設定はVMのメニュー→「構成」からいける(はず)。
f:id:engetu21:20191001190048j:plain
かぶってなければ、前半は好きな文言をいれてドメインを作成できる。また、同画面にてIPアドレスの静的化も可能。

設定後にSSH画面に戻り、ドメインに対しての証明書を発行。
今回はhogehoge.japaneast.cloudapp.azure.comを例として発行してもらいます。

$ sudo certbot-auto certonly -d hogehoge.japaneast.cloudapp.azure.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log

How would you like to authenticate with the ACME CA?

  • - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

1: Spin up a temporary webserver (standalone)
2: Place files in webroot directory (webroot)

  • - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 1
※ここでは1を選択。nginx等を事前に導入しておくと、nginxで使用するかどうかの選択肢が現れる

Plugins selected: Authenticator standalone, Installer None
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for hogehoge.japaneast.cloudapp.azure.com
Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/hogehoge.japaneast.cloudapp.azure.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/hogehoge.japaneast.cloudapp.azure.com/privkey.pem
Your cert will expire on 2019-12-24. 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 certificates, 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

無事作られると祝われます。なお、この際VMのポートは80を開けておかないと通信できずに証明書の発行も失敗する模様なので、一時的でもいいので開けておきましょう。

証明書は赤文字の通り、
/etc/letsencrypt/live/hogehoge.japaneast.cloudapp.azure.com/ の配下に生成されます。
fullchain.pemは中間証明書と証明書が一緒になったものでprivkey.pemは秘密鍵とのこと。

4.BottleでSSL

■参考
blog.motikan2010.com

上記サイトを参考に、以下のように作成しました。

import sys, os, datetime
from bottle import route, run, request, HTTPResponse, ServerAdapter

class SSLWebServer(ServerAdapter):
    def run(self, handler):
        from gevent.pywsgi import WSGIServer
        srv = WSGIServer((self.host, self.port), handler,
        certfile='/etc/letsencrypt/live/hogehoge.japaneast.cloudapp.azure.com/fullchain.pem',
        keyfile='/etc/letsencrypt/live/hogehoge.japaneast.cloudapp.azure.com/privkey.pem')
        srv.serve_forever()

@route('/bottle',  method='GET')
def bottle():
    return '<b>Hello bottle!</b>'

run(host='0.0.0.0', port=8080, server=SSLWebServer)

で、サーバ起動。

$ sudo python ./hellobottle.py

sudoをつけているのは、ブラウザからアクセス時にパーミッションエラーが発生するため。秘密鍵ファイル(下記は実態の方)の権限を直せば不要になります。

$ ls -ltr /etc/letsencrypt/archive/hogehoge.japaneast.cloudapp.azure.com/

  • rw------- 1 root root 1704 Sep 25 22:50 privkey1.pem
  • rw-r--r-- 1 root root 3611 Sep 25 22:50 fullchain1.pem
  • rw-r--r-- 1 root root 1647 Sep 25 22:50 chain1.pem
  • rw-r--r-- 1 root root 1964 Sep 25 22:50 cert1.pem

$ sudo chmod 644 /etc/letsencrypt/archive/hogehoge.japaneast.cloudapp.azure.com/privkey1.pem

  • rw-r--r-- 1 root root 1704 Sep 25 22:50 privkey1.pem
  • rw-r--r-- 1 root root 3611 Sep 25 22:50 fullchain1.pem
  • rw-r--r-- 1 root root 1647 Sep 25 22:50 chain1.pem
  • rw-r--r-- 1 root root 1964 Sep 25 22:50 cert1.pem

f:id:engetu21:20191002080748j:plain
証明書については有効期限が3ヶ月となっているため、手動で更新するかcronで定期的に更新しないといけません。
sudo certbot-auto renew のコマンドで実行できるようなので、設定しておきましょう。