AWSでJupyterHub (JupyterHubへのログイン)

# 概要

全体概要は，[AWSでJupyterHub (概要) ](https://qiita.com/ryouka0122/items/af5004d17e0ac934e550)にあるので，参照してください．

今回は，前回セットアップしたJupyterHubへのログイン周りを固めていきます．
JupyterHubの認証はいくつかあるのですが，今回はPAM認証を利用しています．

前回のままでは，ログインできないので，正しくログインできるように整えてます．

# おしながき
* JupyterHubへのログイン
* 権限の修正
* リトライ
* notebookのディレクトリ変更


# JupterHubへのログイン
実は`ec2-user`でログインしようとすると，ログインできないのです．
どんなに丁寧に入力してもログインできません．

ここで動作確認もかねて，テスト用のアカウント`admin_user`と`test_user`の2つを作っておきます．
以下のコマンドで，ユーザ追加，パスワード設定，JupyterHub用ディレクトリの作成を行います．
ユーザ追加時に`jupyterhub`グループを指定しておきます．
パスワードは自分が分かるものにしておきます．（後で使うので）
ディレクトリは各ユーザのホームディレクトリ配下に`notebook`という名前で作ります．

```bash:アカウント追加
useradd admin_user -g jupyterhub
passwd admin_user
sudo -u admin_user mkdir /home/admin_user/notebook
```

同様に`test_user`も同じコマンドで作成していきます．
次に，`jupyterhub_config.py`にユーザ追加します．
追加の仕方は次のようにします．

```py:/etc/jupyterhub/jupyterhub_config.py
c.Authenticator.admin_users = {
  'ec2-user',
  'admin_user'
}
c.Authenticator.whitelist = {
  'ec2-user',
  'admin_user',
  'test_user'
}
```

追加したら，`jupyterhub`を起動させます．

ログイン画面で，作ったばかりのユーザでログインしてみます．
いずれのユーザもログインに失敗してしまいます．
ログにも同じような情報が出ていると思います．`/var/log/secure`というログにもその時の記録がされています．（`sudo`を使おうとしているため記録されます）
これは，PAM認証がうまく機能していないためです．

## PAM認証とは
Linuxには，各アプリケーションが共通して認証できる機構が備わっています．
それが，PAM(Pluggable Authentication Modules)のようです．
詳しい説明はここではやりません．（あまり知らないので出来ません．．．）


# 実行権限の修正
ユーザ名・パスワードがあってても，Linuxユーザの`jupyterhub`がログインユーザへのsudo権限がないためです．
`jupyterhub`がどのユーザにもsudoが使えるように設定していきます．
sudo権限を管理できる`/etc/sudoers.d/`というディレクトリがあります．実は`ec2-user`の設定がここにあり，`root`同等の権限を持てる設定になってます．
`jupyterhub`というユーザが`jupyterhub`グループに対して，`sudo -u {username} /opt/anaconda3/bin/sudospawner`というコマンドをパスワードなしで実行できるようにします．この手の権限付与はピンポイントでやっておくべきなので，コマンドに対して付与していきます．

```text:/etc/sudoers.d/jupyterhub
## Jupyterhub
Cmnd_Alias JUPYTER_CMD = /opt/anaconda3/bin/sudospawner
%jupyterhub ALL=(jupyterhub) /usr/bin/sudo
jupyterhub ALL=(%jupyterhub) NOPASSWD:JUPYTER_CMD
```

次に，Anacondaに`sudospawner`パッケージを追加します．

```
sudo /opt/anaconda3/bin/conda install -y -c conda-forge sudospawner
```


これとは他に，`jupyterhub`ユーザにPAM認証の権限を付与するために`shadow`グループに追加させる必要があります．
`/etc/shadow`というファイルを操作するため状態を確認しておきます．

```
[root@xxx ~] ls -l /etc/shadow
---------- 1 root root 708 Dec  4 07:41 /etc/shadow
```

権限はrootになっていますが，`000`と読み書きできないファイルになっています．以下のコマンドを実行して，変更していきます．

```bash
# shadowグループの追加
sudo groupadd shadow

# /etc/shadowファイルをshadowグループに変更
sudo chgrp shadow /etc/shadow

# /etc/shadowファイルのshadowグループにread権限追加
sudo chmod g+r /etc/shadow

# jupyterhubユーザをshadowグループに追加
sudo usermod -a -G shadow jupyterhub
```

## /etc/shadowファイルについて
このファイルは，ユーザのパスワード情報が記録されています．
入力したパスワードを指定されたハッシュ化によって得られた値とファイル内のハッシュ値を突き合わせて認証をするようです．
ファイル内の`ec2-user`が，`!!`となっているので，「このユーザにログインできない」というロック状態を意味しているようです．
そのため，JupyterHubでいくらログインしても失敗するようでした．（詳細まで理解できてないです）

# 再度，ログイン
`jupyterhub`の権限が設定出来たら，`jupyterhub`を起動させます．
起動コマンドは以下のようにします．`JupyterHub.spawner_class`のオプションを付けただけです．

```
cd /etc/jupyterhub
sudo -u jupyterhub /opt/anaconda3/bin/jupyterhub --JupyterHub.spawner_class=sudospawner.SudoSpawner
```

起動後，ブラウザでアクセスして，最初に作った`test_user`でログインしてみると，以下のような画面に遷移します．

![ログイン後画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165030/d7fd67fc-9e08-bab7-522a-f16c46536903.png)

ここまで表示できれば，JupyterHubの設定は完了です．

# JupyterHubのホームディレクトリの変更

この時（[AWSでJupyterHub (EC2)](https://qiita.com/ryouka0122/items/2869d2a7c9f8948c7d88)）に追加したEBSに向けさせようと思います．
`/etc/jupyterhub/jupyterhub_config.py`を以下のように修正します．

```py:/etc/jupyterhub/jupyterhub_config.py
# c.Spawner.notebook_dir = '~/notebook'
c.Spawner.notebook_dir = '/mnt/jupyterhub/{username}'
```

修正したら，`/mnt/jupyterhub/`配下に各ユーザのディレクトリを作ります．今回は`test_user`を対象にします．
ディレクトリが出来たら，JupyterHubを再起動させて設定ファイルを反映させます．

```bash:ディレクトリ作成
sudo -u test_user mkdir /mnt/jupyterhub/test_user
```

ログイン後，ブラウザで試しにnotebookを作成します．
`/mnt/jupyterhub/test_user/Untitled.ipynb`というファイルが作成されていれば，`Spawner.notebook_dir`の設定が反映できたことになります．


# まとめ
今回は，JupyterHubのユーザ管理をPAM認証によって制御するための設定を行いました．
`jupyterhub`ユーザへの`sudo`権限の追加，shadowファイルのread権限修正を経て，Linuxユーザでのログインができるようになりました．
また，notebookのディレクトリを追加したEBSに向けさせるようにしました．ストレージを分けることで管理しやすくなると同時に，JupyterHubが稼働するストレージに問題が起きても，notebookのあるストレージに影響が出ないため安全になります．

認証機能は，デフォルトで`PAMAuthenticator`というクラスが機能するのですが，他にもLDAPやGitHubなどのアカウントでログインできるような仕組みがあります．