WebブラウザからLinuxターミナルを操作する ShellInABox を使ってみる

# この記事について
WebブラウザからLinuxターミナルを操作するミドルウェア `shellinabox` (Shell in a box) についてまとめます。

# shellinabox (Shell in a Box)
## shellinabox とは？
`shellinabox` はWebベースのターミナルエミュレータです。Linuxで動く機器に`shellinabox`をインストールすると、http(s)経由で該当機器のターミナルが操作できるようになります。
詳細は https://github.com/shellinabox/shellinabox を参照してみてください。

## そもそもなぜ shellinabox を使うのか？
さまざまな事情で当該機器にsshでアクセスできない場面があるのではないかと思います。

例えば、ネットワーク的に直接接続できない場合。
当該機器がプライベートのネットワーク内にいるような場合、グローバル側から直接当該機器にアクセスすることは当然ながらできません。ポートフォワードすれば済むかもしれませんが、境界の部分にhttp(s)のリバースプロキシを構築して、ネットワーク内部の`shellinabox`を操作する、などという解決案もあります。

この辺は適材適所で構成を考えればいいと思いますが、その方法の1つとして `shellinabox` を使う案もあるのではないかと思います。

# セットアップしてみる
今回は、買ったばかりの Raspberry Pi 4 Model B (Raspbian Buster) を使って、環境を構築してみます。

## shellinabox のインストール
インストール自体は非常にシンプルで、 `apt` を使ってサクッとインストールできます。

```bash
$ sudo apt-get install shellinabox
```

これだけで初期セットアップは完了です。
なお、RedHat系(CentOSなど)も`yum`を使って簡単にインストールできるようです（今回は試していません）。

## shellinabox の動作
`shellinabox`が起動すると、4200番ポートで https の口が開きます。なので、ブラウザでそこにアクセスすればOKです。

## 動作確認
`shellinabox` を動作させている Raspberry Pi と同じネットワークにいるPCから、ブラウザで `https://(Raspberry PiのIPアドレス):4200/` にアクセスします。
標準では自己証明書がインストールされており、ブラウザ上にSSLの証明書エラーが表示されますが、一旦無視して突き進んでみてください。

以下のような感じで、ブラウザ上に見慣れた Linux ターミナルが表示されると思います。
![pi-raspberrypi- - - Shell In A Box 2019-12-6 18-57-46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169018/522a635d-6d6e-9314-fdba-1393378ba64e.png)

いたって簡単にブラウザから Linux ターミナルが操作できるようになりました。めでたしめでたし。

## サービスの停止や再起動について
一般的なサービスと同様に `systemctl` でサービスの停止や再起動などが行えます。

```
# サービスの停止
$ sudo systemctl stop shellinabox.service
# サービスの起動
$ sudo systemctl start shellinabox.service
```

## セキュリティ対策
無事動作させることができましたが、これだけで設定を終わらせることは危険です。
Linuxターミナルをhttp(s)で表に公開することになりますので、それなりのセキュリティ対策は必須です。
\# http(s)で出すときに限らず、sshで出すときも同じですけどね。

セキュリティ対策に正解というものはないですし、いわゆる「銀の弾丸」もありません。
自身の環境や要件に合わせて対策を検討してみてください。自身で検討できないようであればプロに任せることを検討してください。

とりあえずやっておいたほうが良さそうなことを挙げておきます。

- OSのユーザ周りの設定
  - デフォルトで用意されているユーザとパスワードの設定を見直しましょう。
  - 簡単に root でログインできないように設定しましょう。
  - `sudo` で何でも処理できるような設定はやめましょう。
  - 参考: [Raspberry Piの初期設定](https://qiita.com/morinokami/items/aee081085dd679b1ea22)
- ネットワーク周り・ファイヤーウォールの設定
  - アクセスを許すホストやネットワーク帯を制限しましょう。
  - `iptables` `firewalld` `ufw` などのファイヤーウォールのミドルウェアを設定しましょう。
- http(s)の設定
  - basic認証を入れるなどのちょっとした対策でも、それなりの効果はあります。(ただしbasic認証"だけ" のセキュリティ対策はアホです。)
  - `shellinabox` 単体でhttp(s)のセキュリティ対策をすることは困難ですので、`nginx` を介して `shellinabox` を使うように設定する方法が無難です。
  - ざっくり手順は以下に記載します。

### shellinabox + nginx の設定

前述の通り `shellinabox`単体ではhttp(s)の細かい設定ができません。そのため、`nginx`を導入し、`nginx`側でhttp(s)の設定を追加することにします。

#### shellinabox の設定を見直す
`shellinabox` を localhost からしか接続できないようにします。
あわせて、`nginx`側でSSL化させるため、`shellinabox`側では https ではなく http で接続を受け付けるように設定変更します。

```bash
$ sudo vi /etc/default/shellinabox
----------
変更前
SHELLINABOX_ARGS="--no-beep"
----------
変更後
SHELLINABOX_ARGS="--no-beep --localhost-only --disable-ssl"
----------
 
$ sudo systemctl restart shellinabox.service
```

#### nginxをインストールする
```bash
$ sudo apt-get install nginx
```
#### nginx用のSSL証明書を作成する
今回はとりあえず自己証明書を作成します。今どきは無料でSSL証明書を発行することも可能ですので、できれば正規の証明書を作成しましょう。

```bash
$ sudo mkdir /etc/nginx/ssl
$ sudo openssl req -new -x509 -sha256 -newkey rsa:2048 -days 3650 -nodes -out /etc/nginx/ssl/server.pem -keyout /etc/nginx/ssl/server.key
$ sudo chmod 600 /etc/nginx/ssl/*
$ sudo chmod 700 /etc/nginx/ssl
```

#### basic認証用のユーザを設定する
```bash
$ sudo apt-get install apache2-utils
 
$ sudo htpasswd -c /etc/nginx/.htpasswd <ユーザ名>
New password:
Re-type new password:
Adding password for user <ユーザ名>
```

#### nginxの設定をする
```bash
$ sudo vi /etc/nginx/conf.d/default.conf
----------
server {
    listen      8443 ssl;
    server_name _;
 
    ssl_certificate     /etc/nginx/ssl/server.pem;
    ssl_certificate_key /etc/nginx/ssl/server.key;
 
    proxy_set_header    Host                 $host;
    proxy_set_header    X-Real-IP            $remote_addr;
    proxy_set_header    X-Forwarded-Host     $host;
    proxy_set_header    X-Forwarded-Server   $host;
    proxy_set_header    X-Forwarded-For      $proxy_add_x_forwarded_for;
 
    location / {
        auth_basic              "Login Authentication";
        auth_basic_user_file    /etc/nginx/.htpasswd;
 
        proxy_pass      http://127.0.0.1:4200;
    }
}
```

#### nginx を起動する
```bash
$ sudo systemctl start nginx
```
ブラウザから https://(ホスト名):8443/ にアクセスし、動作確認します

## shellinabox のイマイチな点
実際に`shellinabox`を使ってみて、いまいちと感じた点を挙げてみます。

- 複数行のペーストができない  
他所からコピーした文字列をペーストすることはできるのですが、1行単位でしかペーストできません。地味に不便です。
- 別のホストからファイルをコピーすることができない  
`ssh`でターミナルを操作するような場合は`scp`で別ホストからファイルのコピーができますが、ブラウザベースの`shellinabox`では別ホストからファイルをコピーする手段が用意されていません。