ウェブベースのターミナルサーバを用意する

## 概要

情報処理基礎演習をオンライン化しようとすると、UNIX コマンドを使った演習が幾つか問題になりました。学生の個人端末に ssh をインストールしてもらうことも考えましたが、多数の学生からの「うまく接続できません！」というサポート依頼をさばくことは絶望的です。そのため、ブラウザさえあればアクセスできるウェブベースのターミナルサーバを用意することを考えました。

 * https://github.com/shellinabox/shellinabox
 * http://web-console.org/

と2つのソフトウェアを比較してみたところ、対話型のプログラム（例えば、telnet など）を実行できるなどの点で shellinabox の方が優れていましたので、shellinabox を採用しました。

負荷分散とセキュリティを考慮して、以下の構成をとります。

 * shellinabox は、複数台のバックエンドサーバ上で実行する。
 * フロントエンドサーバで、負荷分散とアクセス制御を行う reverse proxy を動かす。

## バックエンドサーバに shellinabox をインストール

### CentOS の場合

バックエンドサーバが CentOS の場合、shellinabox は EPEL のパッケージで配布されているので、まず EPEL のリポジトリを有効化しておくこと。

```shell-session
$ sudo yum install shellinabox
```

shellinaboxd は 4200/tcp で待ち受けるウェブサーバとして動作する。以下のように設定し、SSL を無効化しておく。

```conf:/etc/sysconfig/shellinaboxd
USER=shellinabox
GROUP=shellinabox
CERTDIR=/var/lib/shellinabox
PORT=4200
OPTS="--no-beep --disable-ssl --disable-ssl-menu -s /:LOGIN"
```

設定が完了したら、shellinaboxd を有効化・起動しておく。

```shell-session
$ sudo systemctl enable shellinaboxd
$ sudo systemctl start shellinaboxd
```

### Debian の場合

バックエンドサーバが Debian の場合は、特に何も考えることなく apt でインストールできる。

```shell-session
$ sudo apt install shellinabox
```

shellinaboxd は 4200/tcp で待ち受けるウェブサーバとして動作する。以下のように設定し、SSL を無効化しておく。


```conf:/etc/default/shellinabox
SHELLINABOX_ARGS="--no-beep --localhost-only --disable-ssl --disable-ssl-menu --service /:LOGIN"
```

なお、以下のように `--service` オプションで SSH 接続するサーバを指定すると、shellinaboxd が動作しているサーバにログインする代わりに、指定されたサーバに接続する ssh クライアントとして動作する。

```conf:/etc/default/shellinabox
SHELLINABOX_ARGS="--no-beep --localhost-only --disable-ssl --disable-ssl-menu --service /:SSH:node00.example.net"
```

したがって、shellinabox をバックエンドサーバにインストールする代わりに、フロントエンドサーバにインストールしておくという構成も考えられる。本稿の場合は、フロントエンドサーバの負荷を極力少なくするために、shellinabox はバックエンドサーバにインストールする構成を採った。

### 共通

この段階で、ブラウザで http://localhost:4200/ にアクセスすると、以下のようなログインプロンプトが表示されるはずである。実際にログインしてみて、shellinaboxd が正常に動作していることを確認しておく。

```
sample login:
```

ここまでの設定から、shellinaboxd は 4200/tcp を経由して世界中にログインプロンプトを公開するも同然のデーモンであるから、適切なアクセス制限が前段として必要なことが分かる。

負荷分散とアクセス制御を担当するフロントエンドサーバからの接続のみを受け付けるように iptables などを適切に設定しておく。

## フロントエンドサーバで負荷分散とアクセス制御を行う設定

負荷分散（reverse proxy）とアクセス制御は、apache-2.4 で実現する。最初に必要なモジュールを有効化しておく。

```shell-session
$ sudo a2enmod proxy
$ sudo a2enmod proxy_balancer
$ sudo a2enmod lbmethod_byrequests
```

https://httpd.apache.org/docs/current/en/mod/mod_proxy_balancer.html の例に従って、以下のように設定する。

```conf:/etc/apache2/sites-available/default-ssl.conf
Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
<Proxy balancer://shellcluster>
        BalancerMember http://node00.example.net:4200 route=0
        BalancerMember http://node01.example.net:4200 route=1
        BalancerMember http://node02.example.net:4200 route=2
        ProxySet stickysession=ROUTEID
</Proxy>
ProxyPass /shell/ balancer://shellcluster
ProxyPassReverse /shell/ balancer://shellcluster

<Location /shell/>
        AuthType shibboleth
        ShibRequestSetting requireSession 1
        Require shib-session
</Location>
```

上記設定の前半部分が負荷分散（reverse proxy）の設定で、後半部分がアクセス制御の設定である。shellinabox には、ユーザ名・パスワードの brute force attack などを抑止するための仕掛けが一切ないので、フロントエンド側でアクセス制御しておかねばならない。弊センターの場合、一定回数以上の認証失敗でロックアウトする仕組みが Shibboleth IdP に用意されているので、それを流用している。

## 制限

 * フロントエンドでアクセス制御の認証を行なった上で、さらに shellinabox が表示するログインプロンプトにユーザ名・パスワードを入力しなければならない。
 * X を必要とするプログラムは実行できない。
 * vi や emacs -nw は実行可能だが、日本語を入力すると表示が乱れる。