リモートサーバにJupyterLabを導入し、ローカルからhttpsでアクセス


環境
ローカルPC: MacBook Air(Monterey)
サーバPC: Ubuntu Server 20.04.4
オレオレ証明書を使用
※リモートサーバには固定IPを割り当て

JupyterLab導入時に思ったこと

JupyterLabの導入をネットで調べると、ブラウザのアドレスバーにhttp://と入力させる記事がほとんどだった。しかし、通信のHTTPS化が進むこのご時世、私はJupyterLabのアクセスもhttpsでセキュアにしたかった!

JupyterLabをリモートサーバにインストール

今回はpip3で導入する。(他にもcondaなどで導入できる)

pip3 install jupyterlab

そして、export PATH="$HOME/.local/bin:$PATH"を.zshrcなどに書き込み、sourceコマンドで適用する。

Node.jsが必要

ただ、サーバにNode.jsが導入されていないとJupyterLabのカーネルが起動しないらしい。つまり.ipynbが実行できない...

Node.jsの導入は少しややこしい。

sudo apt install -y nodejs npm
sudo npm install n -g
sudo n stable

 # nodejsとnpmの削除。環境の固定(バージョンアップさせない)ためっぽい?
sudo apt purge -y nodejs npm

HTTPS化の準備

HTTPS通信にはデジタル証明書が必要だ。
しかし、自分用なので認証局に申請するほどのことでも無いし、コミュニティ内のローカル認証局(有るのか?)に申請するのも時間と手間がかかる。

ならば、今すぐに解決する道は1つしか無い ――― オレオレ証明書だ!

1. .cnfファイルを作る

まず、~~~.cnfを作る必要がある。

作成後に元の設定に戻す必要があるため、作業用ディレクトリを作成し、その中で以下を行う。
Ubuntuでは、元となる.cnf/etc/ssl/openssl.cnfの位置にある。

mkdir ~/myopenssl
cd ~/myopenssl
sudo cp /etc/ssl/openssl.cnf ./san.cnf

このsan.cnfという名前でコピーしたファイルの中身の一部を編集する必要がある。

.cnfファイルの編集

以下での有効化は、コメントアウトを外す(#を消す)か、無い場合に追記することを指す。
1. [req]セクションのreq_extensions = v3_reqを有効化

2. どこかに有るcopy_extensions = copyの有効化

3. [ v3_req ]セクションのkeyUsageの次の行に、subjectAltName = IP:192.168.1.2のように自機のIPv4を追加
 ※DNSの場合は、subjectAltName = DNS:xxx.com
 ※複数(マルチ)で書きたい場合は下のリンクを参照
 ※keyUsageがない場合は、セクションの最後にkeyUsage = nonRepudiation, digitalSignature, keyEnciphermentを追加

2. オレオレ証明書の生成

打ち間違えると怖いので、シェルスクリプトにしている。(途中入力あり)

 #!/bin/sh

echo "----- Backup openssl.cnf -----"
cp /etc/ssl/openssl.cnf ./
sudo cp san.cnf /etc/ssl/openssl.cnf

echo ""
echo "----- Generate key -----"
openssl genrsa -out private.key 4096
openssl req -new -x509 -days 365 -key private.key -sha256 -out cert.pem

 # ここで入力が求められる
 # JP、都道府県名、市町村名、所属コミュニティ名、所属部署名、IP の順で入力
 # 所属部署名は空欄でもOK。他は有った方が後で証明書を認識するときに楽。

 # いじる前に戻す
echo ""
echo "----- Restore openssl.cnf -----"
sudo cp openssl.cnf /etc/ssl/openssl.cnf

echo ""
echo "----- Finished -----"

これでprivate.keycert.pemが生成された。(有効期限は365日。意識高い!)
これを後でJupyterLabの設定に使う。

3. ローカルにオレオレ証明書を適用

3-1. ローカルPCにオレオレ証明書をコピー
  scp user1@IPv4:~/myopenssl/cert.pem ./

3-2. オレオレ証明書を開く
  macではopen cert.pemで開いた際に、キーチェーンアクセスというアプリが起動する。そこで表示される一覧の中でオレオレ証明書を見つけ、ダブルクリックで開く。

3-3. 常に信頼に設定する
 信頼タブの中で、この証明書を使用するとき:常に信頼にする。

JupyterLabの設定

1. 設定ファイルの生成

~/.jupyter/jupyter_lab_config.pyが既に存在するなら次へ。
無い場合はjupyter lab --generate-configを実行。

2. パスワード用ハッシュ値の生成

JupyterLabへのログインパスワードと対となるハッシュ値を生成する。

コンソールでipythonを起動し、passwd関数を実行。

from IPython.lib import passwd
passwd()

入力が要求されるので、ログインパスワードを入力。
sha1:なんたらかんたらというハッシュ値が生成されるので、どこかに保存。

3. JupyterLabの設定ファイルを編集

~/.jupyter/jupyter_lab_config.pyを編集する。
以下の内容を末尾に追記する。

c = get_config()
c.ServerApp.certfile = '/home/user1/myopenssl/cert.pem'
c.ServerApp.keyfile = '/home/user1/myopenssl/private.key'
c.IPKernelApp.pylab = 'inline'
c.ServerApp.ip = '0.0.0.0'
c.ServerApp.open_browser = False
c.ServerApp.port = 9999
c.ServerApp.token = '好きなトークン'
c.ServerApp.password = 'sha1:なんたらかんたら'
  • c.ServerApp.certfilec.ServerApp.keyfileの部分は、cert.pemprivate.keyの絶対パス
  • 好きなトークンの部分は英数字の羅列(URLに使われる)
  • passwordは先程生成したハッシュ値

4. ローカルPCのブラウザにブクマ

JupyterLabへのURL
  https://IPv4:9999/lab?token=トークン

  • IPv4:上で設定したIPv4(DNSなら~~~.com)
  • トークン:上で設定した好きなトークン

5. JupyterLabの起動&ログイン

  • サーバのコンソール:jupyter lab
  • ローカルPCのブラウザ:ブクマしたリンクを踏み、パスワードを入力

サーバからログアウトしてもJupyterLabを起動しておきたいなら、screenコマンド開いた仮想ウィンドウ内でjupyter labを実行する。
JupyterLabを終了するときはCtrl + Cした後にyを入力。

最後に

「よし、これでセキュアになった!」と満足してから気がついたが、そもそも内部サーバにはVPNを使ってアクセスしている。HTTPS化は不要だったのでは...?

いや、コミュニティのVPN管理者にも通信内容を把握されなくなるし、VPNもリスクが0な訳ではないので良かったんだ、うん!

セキュリティも関係しますし、何か間違いがあれば是非コメントください。

参考
JupyterLabインストール - https://dev.classmethod.jp/articles/jupyterlab_mat_s3/
証明書の設定1 - https://kaede.jp/2018/06/10191854/
証明書の設定(マルチ) - https://rms.ne.jp/sslserver/csr/openssl-html/
証明書の設定2 - https://qiita.com/rimksky/items/0cb8cf2921d6b7cfe25e
証明書のコマンド - https://moewe-net.com/uncategorized/openssl-create-certificate
証明書・opensslコマンド集 - https://qiita.com/takech9203/items/5206f8e2572e95209bbc
JupyterLabの設定 - https://qiita.com/RayDoe/items/e1ec21c63a15adb1a061