Jupyter HubとAmazon Cognitoの連携手順

シングルサーバのJupyter HubにAmazon Cognitoのユーザでサインインできるようにする手順
TLS化にはLet's Encryptを使用するが、Amazon EC2のパブリックドメインは許可されない
Azure VMのパブリックドメインは許可されるので、Jupyter HubのサーバはAzure VMで構築する
なおIDサービスとしてAzureADを使用するには管理者権限が必要な場合があるため、手軽なAmazon Cognitoを使用する

### 環境
- サーバ: Azure VM
- サーバスペック: Standard B2s (2 vcpu 数、4 GiB メモリ)
- OS: Ubuntu 20.04 LTS - Gen 2
- Python 3.8.10
- jupyterhub==2.2.0

### この手順でやらないこと
- Jupyter Hubサービス化
- 証明書自動更新
- DockerSpawnerの使用
など..

### 1. Azure VM構築
1. Azure VMを構築する
1. Let's Encrypt検証のため、port 80を全開放する
1. パブリックIPにDNSラベルを入力する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481044/b885e88e-04f9-f11a-04ae-fd56aad81ff2.png)

### 2. サーバ設定
1. Jupyter Hub設定
   ```shell:shell
   # 準備
   # 以降全てrootでの操作
   sudo su -
   apt update
   # python3はデフォルトを使う
   python3 --version
   apt install -y python3-pip
   python3 -m pip install -U pip
   apt install -y nodejs npm
   
   # Jupyter Hubなどインストール
   python3 -m pip install jupyterhub
   npm install -g configurable-http-proxy
   python3 -m pip install jupyterlab notebook
   # インストールテスト
   jupyterhub -h
   configurable-http-proxy -h
   
   # Jupyter Hub設定フォルダ作成
   mkdir /etc/jupyterhub
   # Jupyter Hub設定ファイル作成
   jupyterhub --generate-config -f /etc/jupyterhub/jupyterhub_config.py
   # 設定ファイルを使用してJupyter Hubを起動　"http://{Azure VMのFQDN}:8000"でアクセスできるか確認
   jupyterhub -f /etc/jupyterhub/jupyterhub_config.py
   ```
2. Let's Encrypt設定
   ```shell:shell
   apt install -y software-properties-common
   apt install -y certbot
   
   certbot certonly --standalone
   # 1. emailアドレスを入力
   # 2. (A)gree押下
   # 3. (Y)es押下
   # 4. Azure VMのFQDNを入力
   # この時port 80が全開放になってないとverifyに失敗する
   
   # fullchain.pemとprivkey.pemが出力されているか確認
   ll /etc/letsencrypt/live/{Azure VMのFQDN}
   ```
   /etc/jupyterhub/jupyterhub_config.pyを編集する
   ```python3:/etc/jupyterhub/jupyterhub_config.py
   c.JupyterHub.ssl_cert = '/etc/letsencrypt/live/{Azure VMのFQDN}/fullchain.pem'
   c.JupyterHub.ssl_key = '/etc/letsencrypt/live/{Azure VMのFQDN}/privkey.pem'
   c.JupyterHub.port = 443
   ```
   ```shell:shell
   # 設定ファイルを使用してJupyter Hubを起動　"https://{Azure VMのFQDN}"でアクセスできるか確認
   jupyterhub -f /etc/jupyterhub/jupyterhub_config.py
   ```

### 3. Amazon Cognito連携
1. 以下設定値でCognito ユーザプールを作成する
指定がない項目については基本任意の値 or デフォルト値でOK
    1. [認証プロバイダー] -> [Cognito ユーザープールのサインインオプション] -> [ユーザー名]チェック
    1. [セルフサービスのサインアップ] -> [自己登録] -> [自己登録を有効化]チェックを外す
    1. [ホストされた認証ページ] -> [Cognito のホストされた UI を使用]チェック
    1. [最初のアプリケーション] -> [アプリケーションタイプ] -> [秘密クライアント]を選択
    1. [クライアントのシークレット]-> [クライアントのシークレットを生成する]を選択
    1. [許可されているコールバック URL]に"https://{Azure VMのFQDN}/hub/oauth_callback"を入力
    1. [許可されているサインアウト URL - オプション] -> [サインアウトURLを追加]で"https://{Azure VMのFQDN}"入力

1. Jupyter Hub OAuth2設定
   ```shell:shell
   # oauthenticatorインストール
   pip3 install oauthenticator
   ```
   ```python3:/etc/jupyterhub/jupyterhub_config.py
   # ファイルの先頭に書く
   from oauthenticator.generic import GenericOAuthenticator
   
   c.Spawner.cmd = ['jupyterhub-singleuser']
   
   c.JupyterHub.authenticator_class = GenericOAuthenticator
   c.OAuthenticator.oauth_callback_url = "https://{Azure VMのFQDN}/hub/oauth_callback"
   c.OAuthenticator.client_id = "{CognitoのアプリケーションクライアントID}"
   c.OAuthenticator.client_secret = "{Cognitoのアプリケーションクライアントシークレット}"
   
   c.GenericOAuthenticator.login_service = "AWSCognito"
   c.GenericOAuthenticator.username_key = "username"
   c.GenericOAuthenticator.authorize_url = "{Cognitoドメイン}/oauth2/authorize"
   c.GenericOAuthenticator.token_url = "{Cognitoドメイン}/oauth2/token"
   c.GenericOAuthenticator.userdata_url = "{Cognitoドメイン}/oauth2/userInfo"
   ```

### 4. 動作確認
1. Cognitoユーザ作成
ユーザ名は"qiita"にする
1. OSユーザ作成とJupyter Hub起動
    ```shell:shell
    # Jupyter Hubユーザが使用するhome directoryごと作成する
    useradd -m qiita
    jupyterhub -f /etc/jupyterhub/jupyterhub_config.py
    ```
1. Jupyter Hubにアクセス
   1. "https://{Azure VMのFQDN}"にアクセス
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481044/661ed048-1cfd-9d0f-3074-1ec64e557181.png)
   1. Cognitoのユーザ"qiita"でsignin
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481044/0f8541b7-639f-9dbc-b6e5-4faed3cf9f49.png)
   1. Python 動作
   pip installの後モジュールが見つからない場合はkernelをrestart
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481044/7f702736-ddad-69d8-6168-40d8e2745c70.png)
   1. logoutでトップページに戻る