多段sshとchroot環境。そしていろいろなコマンドを使いたい

この記事は[Linux Advent Calendar 2020](https://qiita.com/advent-calendar/2020/linux)の7日目の記事です。

外部からの接続を許し、かつ内部でほかのデータを触れないようにするためにchrootを用いて環境構築をしたので、なにを行ったかを紹介します。ツッコミどころがありましたら教えていただければと思います。
また、最後にできなかったことを書いておきます。主にGPU。

#やりたいこと
- ユーザーは踏み台サーバを経由して、計算用サーバにsshでアクセスする
- 踏み台サーバ・計算用サーバともにそのユーザのディレクトリ以外のデータにはアクセスできないようにしたい
    - そのためにchrootを使う。踏み台サーバ・計算用サーバともに。
- けどいろんなコマンドとかは使いたいよね！


#やること
1. 各サーバでユーザ・ホームディレクトリを作成
2. 基本的なコマンドが使えるようにchroot配下にいろいろコピーする
3. そのユーザをchroot配下におきつつ、sshをできるようにする
4. **種々のコマンドを使えるようにする**。これがしんどい。

順番にとりあげていきます！

なお、めんどくさいので、以下各サーバのホームディレクトリを下記のようにします。

```bash
HOMEDIR=/path/to/homedir
PARENTDIR=(HOMEDIRの親ディレクトリ)
USERNAME=(ユーザ名)
```

また、踏み台サーバと計算用サーバの話が入り混じりますが、ともにユーザ名・ホームディレクトリへのパスは同じものとします。

#各サーバでユーザ・ホームディレクトリを作成する
まず最初にユーザやホームディレクトリがないと始まらないので、ユーザを作成します。

```bash
useradd -b ${PARENTDIR} -m -N -s /bin/bash ${USERNAME}
```

一応パスワードも設定しておきました。

```bash
passwd ${USERNAME}
```

また、書き込み可能なディレクトリを作成するため、こんなこともしました。

```bash
mkdir ${HOMEDIR}/home
chown ${USERNAME}:users ${HOMEDIR}/home
```

#基本的なコマンドが使えるようにchroot配下にいろいろコピーする
[chrootを用いてSSHユーザのディレクトリを制限する](https://hacknote.jp/archives/32888/)を参考にしました。いろいろなものをパーミッションや所有者情報をそのままにコピーしていきます。ポイントはchownやchmodを忘れないことでしょうか。

```bash
cd ${HOMEDIR}
cp -p -r /bin ${HOMEDIR}/bin
cp -p -r /lib ${HOMEDIR}/lib
cp -p -r /lib64 ${HOMEDIR}/lib64
mkdir ${HOMEDIR}/usr
cp -p -r /usr/bin ${HOMEDIR}/usr/bin
cp -p -r /usr/lib ${HOMEDIR}/usr/lib
cp -p -r /usr/lib64 ${HOMEDIR}/usr/lib64
chown root:root ${HOMEDIR}
chmod 755 ${HOMEDIR}
cd ${HOMEDIR}
chown ${USERNAME}:users *
```

これでここにアクセスできればそのユーザは多少のことはできるようになります。できないことのほうが多いですが…。

#ユーザをchroot配下におきつつ、sshをできるようにする
##sshの設定
sshができるようにします。

```bash
cd ${HOMEDIR}
mkdir .ssh
vi .ssh/authorized_keys
chmod 700 .ssh
chmod 600 .ssh/authorized_keys
chown -R ${USERNAME}:users ${HOMEDIR}
```

##chrootの設定
他の領域に入れないように設定します。
必要であれば、sshの`AllowUsers`にも`${USERNAME}`を入れます。`sshd_config`の中の`${USERNAME}`や`${HOMEDIR}`は展開したものを書いて下さい。

```bash
vi /etc/ssh/sshd_config
######################
# 末尾に以下を追記
Match User ${USERNAME}
    ChrootDirectory ${HOMEDIR}
    X11Forwarding no
    AllowTcpForwarding no
    PubkeyAuthentication yes
    AuthorizedKeysFile .ssh/authorized_keys
#####################
# service sshd restart や systemctl sshd restartでもいいとは思います
/etc/init.d/ssh reload
```

ただし、踏み台サーバを経由して多段sshしたい場合には、踏み台サーバ側の`AllowTcpForwarding`は`yes`にする必要があります。ご注意ください。

#いろいろなコマンドを使うための設定(その1)
vimコマンドなど多くのコマンドは互換性維持などのため、`/usr/bin/vim`がシンボリックリンクになっています。例えば筆者の環境では、`/usr/bin`にパスが通っているため、`/usr/bin/vim`にアクセスするとこれがシンボリックリンクのために`/etc/alternatives/vim`を介し、さらにこれもシンボリックリンクのため`/usr/bin/vim.basic`にアクセスすることで実行されます。つまり、

```
vim -> /usr/bin/vim -> /etc/alternatives/vim -> /usr/bin/vim.basic(これが実体)
```
のように伝わっていきます。というわけで必要なディレクトリをコピーします。

```bash
cd ${HOMEDIR}
mkdir ${HOMEDIR}/etc
cp -p -r /etc/alternatives ${HOMEDIR}/etc/alternatives
```

#踏み台サーバの設定
##sshのための設定
###${HOMEDIR}/etc/passwdが必要
踏み台サーバ->計算用サーバのsshのために`/etc/passwd`が必要でした。

```bash
-bash-4.3$ ssh ${USERNAME}@(計算用サーバ)
No user exists for uid (${USERNAME}のuid)
```

そのため、`etc/passwd`を作ってやります。`${USERNAME}`は展開してください。

```bash
mkdir ${HOMEDIR}/etc
vi ${HOMEDIR}/etc/passwd
#========
${USERNAME}:x:(踏み台サーバの${USERNAME}のuid):100::/:/bin/bash
#========
```

###/dev/random等が必要
`/dev/random`と`/dev/urandom`が必要です。

```bash
mknod ${HOMEDIR}/dev/random c 1 9
mknod ${HOMEDIR}/dev/urandom c 1 9
```
で作成可能ですが、/dev/ttyをマウントする方法でも問題ないです。

##sshに/dev/ttyが必要
踏み台サーバ経由で計算用サーバにsshする必要があるのですが、sshの際に仮想コンソールを作成するために、`debug1: read_passphrase: can't open /dev/tty: No such device or address`となってしまうため、`/dev/tty`が必要になります。これの対処には2つ方法があるのを見つけています。

###/dev/ttyをマウントする
ある程度脆弱性が生まれるのは覚悟の上です。[chroot環境のユーザ用にdev,procをmountする](https://hogem.hatenablog.com/entry/20090925/1253850339)を参考にしました。

```bash
mkdir ${HOMEDIR}/dev
mount --bind /dev ${HOMEDIR}/dev
```

マウントだと再起動したらだめじゃん！というツッコミは甘んじて受け入れます。fstab使って下さい。

###がんばって/dev/ttyを作成する
[LinuxでchrootによるJail環境を構築2](http://takesy.cocolog-nifty.com/atico/2010/08/linuxchrootjail.html)によるとこんな方法もあるらしいです。

```bash
mkdir ${HOMEDIR}/dev
mknod -m 666 ${HOMEDIR}/dev/tty c 5 0
mknod -m 660 ${HOMEDIR}/dev/tty0 c 4 0
mknod -m 600 ${HOMEDIR}/dev/tty1 c 4 1
```

踏み台サーバはsshができればいいのでこんなもんです。

#計算用サーバの設定
こちらはもっといろいろ設定しました。`htop`は使いたいしgitも使いたいしCやPythonも使いたいし…。というわけで順番に解決していきます。

##webへのアクセスで名前解決したい
`wget`などがそもそも使えませんでした。名前解決できていなかったのです。

```bash

cp -p /etc/resolv.conf ${HOMEDIR}/etc/
```

##/dev内にいろいろほしい
下記で`screen`コマンドが使いたいのでいろいろやりました。あとnullが必要なことも。踏み台サーバと同様に2つの方法があります

###/devをマウント
マウントするのは手っ取り早いです。

```bash
mkdir ${HOMEDIR}/dev
mount --bind /dev ${HOMEDIR}/dev
```

###がんばっていろいろつくる
これでもできます

```bash
mkdir ${HOMEDIR}/dev
mknod -m 666 ${HOMEDIR}/dev/null c 1 3
mknod -m 666 ${HOMEDIR}/dev/zero c 1 5
mknod -m 644 ${HOMEDIR}/dev/random c 1 8
mknod -m 644 ${HOMEDIR}/dev/urandom c 1 9
mknod -m 666 ${HOMEDIR}/dev/tty c 5 0
mknod -m 660 ${HOMEDIR}/dev/tty0 c 4 0
mknod -m 600 ${HOMEDIR}/dev/tty1 c 4 1
```

##scpで受信するのにpasswdが必要
ssh叩けるようになったのに受信できませんでした。passwdが必要そうです。`${USERNAME}`は展開してください

```bash
mkdir ${HOMEDIR}/etc
vi ${HOMEDIR}/etc/passwd
#========
${USERNAME}:x:(踏み台サーバの${USERNAME}のuid):100::/:/bin/bash
#========
```

##top/htopなどが見たいよね
わざわざ*計算用サーバ*と言っているように、計算用なのでhtopなどが見たいです。こればかりは`/proc`を参照できないといけません。仕方ないのでマウントします。

```bash
mkdir ${HOMEDIR}/proc
mount --bind /proc ${HOMEDIR}/proc
```

#git系やwgetでssl証明書の確認をしたい
近年はhttps化が進んでいますね。ちゃんとhttps通信するために、ssl証明書の確認が必要です。

```bash
mkdir ${HOMEDIR}/etc/ssl
mkdir ${HOMEDIR}/etc/ssl/certs
mount --bind /etc/ssl/certs ${HOMEDIR}/etc/ssl/certs
```

#Cの標準ライブラリが使いたいこともある

```bash
cp -p -r /usr/include ${HOMEDIR}/usr/include
```

#Pythonのビルドがしたい
そのままではPythonのビルドができませんでした。`tmp`が必要なんですね。作ります。

```
mkdir ${HOMEDIR}/tmp
chmod 777 mkdir ${HOMEDIR}/tmp
```

#lsb_releaseが通らない対策
存在しないので通らなかった。

```bash
cp -R /usr/share/ ${HOMEDIR}/usr/share
```

# Pythonで必要かも
これがなかったら動かなかったので。

```bash
mount --bind /dev/shm ${HOMEDIR}/dev/shm
```

#screenコマンドを使いたい
計算用に`screen`をよく使っています。[How do I use the terminal SCREEN when chrooted?](https://superuser.com/questions/487013/how-do-i-use-the-terminal-screen-when-chrooted)を参考にしました。

```bash
mkdir ${HOMEDIR}/run
mkdir ${HOMEDIR}/run/screen
chmod 755 ${HOMEDIR}/run
chmod 777 ${HOMEDIR}/run/screen
mkdir ${HOMEDIR}/dev/pts
mount -t devpts none ${HOMEDIR}/dev/pts/ -o ptmxmode=0666,newinstance
ln -fs /dev/pts/ptmx ${HOMEDIR}/dev/ptmx
```

#できなかったこと
- `nvidia-smi`が通っていません。NVIDIAドライバを用いたGPUの計算ができない…。
- dockerも素直に使えなかった。